From e50ef75f7ef64f11c205da0fe45dfbe0dfdeb26a Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 12 Sep 2017 16:01:07 -0600 Subject: [PATCH] Retire Packaging Deb project repos This commit is part of a series to retire the Packaging Deb project. Step 2 is to remove all content from the project repos, replacing it with a README notification where to find ongoing work, and how to recover the repo if needed at some future point (as in https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project). Change-Id: Id80e2fd6d0f5f1873bd0b11403d19e86de400530 --- .coveragerc | 7 - .gitignore | 26 - .gitreview | 4 - .mailmap | 6 - .testr.conf | 4 - CONTRIBUTING.rst | 18 - HACKING.rst | 24 - LICENSE | 209 --- README | 14 + README.rst | 64 - babel.cfg | 1 - bindep.txt | 23 - doc/.gitignore | 1 - doc/Makefile | 90 -- doc/source/conf.py | 232 ---- doc/source/history.rst | 1 - doc/source/index.rst | 54 - doc/source/using-api-v2.rst | 125 -- doc/source/using-api-v3.rst | 140 -- doc/source/using-sessions.rst | 200 --- examples/pki/certs/cacert.pem | 23 - examples/pki/certs/middleware.pem | 50 - examples/pki/certs/signing_cert.pem | 22 - examples/pki/certs/ssl_cert.pem | 22 - examples/pki/cms/auth_token_revoked.json | 88 -- examples/pki/cms/auth_token_revoked.pem | 79 -- examples/pki/cms/auth_token_revoked.pkiz | 1 - examples/pki/cms/auth_token_scoped.json | 88 -- examples/pki/cms/auth_token_scoped.pem | 78 -- examples/pki/cms/auth_token_scoped.pkiz | 1 - .../pki/cms/auth_token_scoped_expired.json | 88 -- .../pki/cms/auth_token_scoped_expired.pem | 76 -- .../pki/cms/auth_token_scoped_expired.pkiz | 1 - examples/pki/cms/auth_token_unscoped.json | 26 - examples/pki/cms/auth_token_unscoped.pem | 29 - examples/pki/cms/auth_token_unscoped.pkiz | 1 - examples/pki/cms/auth_v3_token_revoked.json | 140 -- examples/pki/cms/auth_v3_token_revoked.pem | 123 -- examples/pki/cms/auth_v3_token_revoked.pkiz | 1 - examples/pki/cms/auth_v3_token_scoped.json | 140 -- examples/pki/cms/auth_v3_token_scoped.pem | 123 -- examples/pki/cms/auth_v3_token_scoped.pkiz | 1 - examples/pki/cms/revocation_list.der | 0 examples/pki/cms/revocation_list.json | 1 - examples/pki/cms/revocation_list.pem | 20 - examples/pki/cms/revocation_list.pkiz | 1 - examples/pki/gen_cmsz.py | 117 -- examples/pki/gen_pki.sh | 208 --- examples/pki/private/cakey.pem | 28 - examples/pki/private/signing_key.pem | 28 - examples/pki/private/ssl_key.pem | 28 - examples/pki/run_all.sh | 30 - keystoneclient/__init__.py | 78 -- keystoneclient/_discover.py | 333 ----- keystoneclient/access.py | 886 ------------- keystoneclient/adapter.py | 223 ---- keystoneclient/auth/__init__.py | 38 - keystoneclient/auth/base.py | 374 ------ keystoneclient/auth/cli.py | 97 -- keystoneclient/auth/conf.py | 132 -- keystoneclient/auth/identity/__init__.py | 37 - keystoneclient/auth/identity/access.py | 48 - keystoneclient/auth/identity/base.py | 422 ------ .../auth/identity/generic/__init__.py | 21 - keystoneclient/auth/identity/generic/base.py | 192 --- keystoneclient/auth/identity/generic/cli.py | 84 -- .../auth/identity/generic/password.py | 89 -- keystoneclient/auth/identity/generic/token.py | 48 - keystoneclient/auth/identity/v2.py | 242 ---- keystoneclient/auth/identity/v3/__init__.py | 30 - keystoneclient/auth/identity/v3/base.py | 265 ---- keystoneclient/auth/identity/v3/federated.py | 121 -- keystoneclient/auth/identity/v3/password.py | 97 -- keystoneclient/auth/identity/v3/token.py | 65 - keystoneclient/auth/token_endpoint.py | 62 - keystoneclient/base.py | 549 -------- keystoneclient/baseclient.py | 46 - keystoneclient/client.py | 63 - keystoneclient/common/__init__.py | 0 keystoneclient/common/cms.py | 444 ------- keystoneclient/contrib/__init__.py | 0 keystoneclient/contrib/auth/__init__.py | 0 keystoneclient/contrib/auth/v3/__init__.py | 0 keystoneclient/contrib/auth/v3/oidc.py | 211 --- keystoneclient/contrib/auth/v3/saml2.py | 920 -------------- keystoneclient/contrib/ec2/__init__.py | 0 keystoneclient/contrib/ec2/utils.py | 287 ----- keystoneclient/discover.py | 364 ------ keystoneclient/exceptions.py | 437 ------- keystoneclient/fixture/__init__.py | 56 - keystoneclient/fixture/discovery.py | 38 - keystoneclient/fixture/exception.py | 20 - keystoneclient/fixture/v2.py | 20 - keystoneclient/fixture/v3.py | 26 - keystoneclient/generic/__init__.py | 4 - keystoneclient/generic/client.py | 208 --- keystoneclient/httpclient.py | 919 -------------- keystoneclient/i18n.py | 27 - keystoneclient/service_catalog.py | 432 ------- keystoneclient/session.py | 1020 --------------- keystoneclient/tests/__init__.py | 0 keystoneclient/tests/functional/__init__.py | 0 keystoneclient/tests/functional/base.py | 89 -- .../tests/functional/hooks/post_test_hook.sh | 50 - .../tests/functional/test_access.py | 50 - keystoneclient/tests/functional/test_base.py | 28 - .../tests/functional/v2_0/__init__.py | 0 .../tests/functional/v3/__init__.py | 0 .../tests/functional/v3/client_fixtures.py | 250 ---- .../tests/functional/v3/test_credentials.py | 194 --- .../functional/v3/test_domain_configs.py | 106 -- .../tests/functional/v3/test_domains.py | 97 -- .../tests/functional/v3/test_ec2.py | 92 -- .../functional/v3/test_endpoint_filters.py | 86 -- .../functional/v3/test_endpoint_groups.py | 123 -- .../tests/functional/v3/test_endpoints.py | 141 --- .../tests/functional/v3/test_federation.py | 106 -- .../tests/functional/v3/test_groups.py | 94 -- .../tests/functional/v3/test_implied_roles.py | 74 -- .../tests/functional/v3/test_policies.py | 89 -- .../tests/functional/v3/test_projects.py | 190 --- .../tests/functional/v3/test_regions.py | 85 -- .../tests/functional/v3/test_roles.py | 236 ---- .../tests/functional/v3/test_services.py | 106 -- .../tests/functional/v3/test_users.py | 140 -- keystoneclient/tests/unit/__init__.py | 0 .../tests/unit/apiclient/__init__.py | 0 .../tests/unit/apiclient/test_exceptions.py | 66 - keystoneclient/tests/unit/auth/__init__.py | 0 keystoneclient/tests/unit/auth/test_access.py | 64 - keystoneclient/tests/unit/auth/test_auth.py | 38 - keystoneclient/tests/unit/auth/test_cli.py | 197 --- keystoneclient/tests/unit/auth/test_conf.py | 178 --- .../tests/unit/auth/test_default_cli.py | 92 -- .../tests/unit/auth/test_identity_common.py | 505 -------- .../tests/unit/auth/test_identity_v2.py | 328 ----- .../tests/unit/auth/test_identity_v3.py | 570 --------- .../unit/auth/test_identity_v3_federated.py | 99 -- .../tests/unit/auth/test_loading.py | 46 - .../tests/unit/auth/test_password.py | 99 -- keystoneclient/tests/unit/auth/test_token.py | 52 - .../tests/unit/auth/test_token_endpoint.py | 67 - keystoneclient/tests/unit/auth/utils.py | 202 --- keystoneclient/tests/unit/client_fixtures.py | 744 ----------- keystoneclient/tests/unit/generic/__init__.py | 0 .../tests/unit/generic/test_client.py | 68 - keystoneclient/tests/unit/test_base.py | 204 --- keystoneclient/tests/unit/test_cms.py | 201 --- keystoneclient/tests/unit/test_discovery.py | 838 ------------ keystoneclient/tests/unit/test_ec2utils.py | 306 ----- keystoneclient/tests/unit/test_fixtures.py | 251 ---- keystoneclient/tests/unit/test_http.py | 218 ---- keystoneclient/tests/unit/test_https.py | 106 -- keystoneclient/tests/unit/test_keyring.py | 201 --- keystoneclient/tests/unit/test_session.py | 1127 ----------------- keystoneclient/tests/unit/test_utils.py | 134 -- keystoneclient/tests/unit/utils.py | 184 --- keystoneclient/tests/unit/v2_0/__init__.py | 0 .../tests/unit/v2_0/client_fixtures.py | 127 -- keystoneclient/tests/unit/v2_0/test_access.py | 217 ---- keystoneclient/tests/unit/v2_0/test_auth.py | 268 ---- .../tests/unit/v2_0/test_certificates.py | 40 - keystoneclient/tests/unit/v2_0/test_client.py | 220 ---- .../tests/unit/v2_0/test_discovery.py | 84 -- keystoneclient/tests/unit/v2_0/test_ec2.py | 107 -- .../tests/unit/v2_0/test_endpoints.py | 147 --- .../tests/unit/v2_0/test_extensions.py | 63 - keystoneclient/tests/unit/v2_0/test_roles.py | 121 -- .../tests/unit/v2_0/test_service_catalog.py | 207 --- .../tests/unit/v2_0/test_services.py | 129 -- .../tests/unit/v2_0/test_tenants.py | 366 ------ keystoneclient/tests/unit/v2_0/test_tokens.py | 217 ---- keystoneclient/tests/unit/v2_0/test_users.py | 301 ----- keystoneclient/tests/unit/v2_0/utils.py | 90 -- keystoneclient/tests/unit/v3/__init__.py | 0 .../tests/unit/v3/client_fixtures.py | 159 --- .../xml/ADFS_RequestSecurityTokenResponse.xml | 132 -- .../tests/unit/v3/examples/xml/ADFS_fault.xml | 19 - .../tests/unit/v3/saml2_fixtures.py | 281 ---- keystoneclient/tests/unit/v3/test_access.py | 211 --- keystoneclient/tests/unit/v3/test_auth.py | 372 ------ .../tests/unit/v3/test_auth_manager.py | 64 - .../tests/unit/v3/test_auth_oidc.py | 188 --- .../tests/unit/v3/test_auth_saml2.py | 714 ----------- keystoneclient/tests/unit/v3/test_client.py | 270 ---- .../tests/unit/v3/test_credentials.py | 33 - keystoneclient/tests/unit/v3/test_discover.py | 82 -- .../tests/unit/v3/test_domain_configs.py | 96 -- keystoneclient/tests/unit/v3/test_domains.py | 53 - keystoneclient/tests/unit/v3/test_ec2.py | 107 -- .../tests/unit/v3/test_endpoint_filter.py | 293 ----- .../tests/unit/v3/test_endpoint_groups.py | 34 - .../tests/unit/v3/test_endpoint_policy.py | 242 ---- .../tests/unit/v3/test_endpoints.py | 104 -- .../tests/unit/v3/test_federation.py | 584 --------- keystoneclient/tests/unit/v3/test_groups.py | 58 - keystoneclient/tests/unit/v3/test_oauth1.py | 290 ----- keystoneclient/tests/unit/v3/test_policies.py | 31 - keystoneclient/tests/unit/v3/test_projects.py | 314 ----- keystoneclient/tests/unit/v3/test_regions.py | 37 - .../tests/unit/v3/test_role_assignments.py | 262 ---- keystoneclient/tests/unit/v3/test_roles.py | 824 ------------ .../tests/unit/v3/test_service_catalog.py | 279 ---- keystoneclient/tests/unit/v3/test_services.py | 44 - .../tests/unit/v3/test_simple_cert.py | 40 - keystoneclient/tests/unit/v3/test_tokens.py | 163 --- keystoneclient/tests/unit/v3/test_trusts.py | 128 -- keystoneclient/tests/unit/v3/test_users.py | 309 ----- keystoneclient/tests/unit/v3/utils.py | 373 ------ keystoneclient/utils.py | 126 -- keystoneclient/v2_0/__init__.py | 6 - keystoneclient/v2_0/certificates.py | 40 - keystoneclient/v2_0/client.py | 220 ---- keystoneclient/v2_0/ec2.py | 60 - keystoneclient/v2_0/endpoints.py | 48 - keystoneclient/v2_0/extensions.py | 31 - keystoneclient/v2_0/roles.py | 91 -- keystoneclient/v2_0/services.py | 50 - keystoneclient/v2_0/tenants.py | 169 --- keystoneclient/v2_0/tokens.py | 127 -- keystoneclient/v2_0/users.py | 131 -- keystoneclient/v3/__init__.py | 7 - keystoneclient/v3/auth.py | 69 - keystoneclient/v3/client.py | 332 ----- keystoneclient/v3/contrib/__init__.py | 2 - keystoneclient/v3/contrib/endpoint_filter.py | 163 --- keystoneclient/v3/contrib/endpoint_policy.py | 155 --- .../v3/contrib/federation/__init__.py | 13 - keystoneclient/v3/contrib/federation/base.py | 40 - keystoneclient/v3/contrib/federation/core.py | 31 - .../v3/contrib/federation/domains.py | 19 - .../contrib/federation/identity_providers.py | 113 -- .../v3/contrib/federation/mappings.py | 153 --- .../v3/contrib/federation/projects.py | 19 - .../v3/contrib/federation/protocols.py | 146 --- keystoneclient/v3/contrib/federation/saml.py | 79 -- .../contrib/federation/service_providers.py | 106 -- keystoneclient/v3/contrib/oauth1/__init__.py | 13 - .../v3/contrib/oauth1/access_tokens.py | 51 - keystoneclient/v3/contrib/oauth1/auth.py | 55 - keystoneclient/v3/contrib/oauth1/consumers.py | 54 - keystoneclient/v3/contrib/oauth1/core.py | 66 - .../v3/contrib/oauth1/request_tokens.py | 73 -- keystoneclient/v3/contrib/oauth1/utils.py | 38 - keystoneclient/v3/contrib/simple_cert.py | 41 - keystoneclient/v3/contrib/trusts.py | 102 -- keystoneclient/v3/credentials.py | 143 --- keystoneclient/v3/domain_configs.py | 130 -- keystoneclient/v3/domains.py | 127 -- keystoneclient/v3/ec2.py | 98 -- keystoneclient/v3/endpoint_groups.py | 136 -- keystoneclient/v3/endpoints.py | 175 --- keystoneclient/v3/groups.py | 145 --- keystoneclient/v3/policies.py | 130 -- keystoneclient/v3/projects.py | 222 ---- keystoneclient/v3/regions.py | 119 -- keystoneclient/v3/role_assignments.py | 125 -- keystoneclient/v3/roles.py | 536 -------- keystoneclient/v3/services.py | 140 -- keystoneclient/v3/tokens.py | 111 -- keystoneclient/v3/users.py | 300 ----- releasenotes/notes/.placeholder | 0 ...red-flag-to-validate-25b8914f4deb359b.yaml | 5 - .../bp-domain-config-9566e672a98f4e7f.yaml | 7 - ...ssword-expired-users-b0c4b1bbdcf33f16.yaml | 6 - .../notes/bug-1616105-cc8b85eb056e99e2.yaml | 8 - .../notes/bug-1641674-4862454115265e76.yaml | 8 - .../notes/bug-1654847-d2e9df994c7b617f.yaml | 5 - .../deprecated_auth-d2a2bf537bdb88d3.yaml | 12 - .../notes/implied_roles-ea39d3c3d998d482.yaml | 3 - .../notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml | 17 - ...ole_assignment_names-7e1b7eb8c2d22d7c.yaml | 6 - ...ove-credentials-data-46ab3c3c248047cf.yaml | 8 - .../remove-middleware-eef8c40117b465aa.yaml | 10 - ...apiclient_exceptions-0cd5c8d16aa09a22.yaml | 5 - ...apiclient_exceptions-6580003a885db286.yaml | 10 - .../notes/remove_cli-d2c4435ba6a09b79.yaml | 7 - ...moved-generic-client-ff505b2b01bc9302.yaml | 6 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/_templates/.placeholder | 0 releasenotes/source/conf.py | 285 ----- releasenotes/source/index.rst | 11 - releasenotes/source/mitaka.rst | 6 - releasenotes/source/newton.rst | 6 - releasenotes/source/ocata.rst | 6 - releasenotes/source/unreleased.rst | 5 - requirements.txt | 16 - setup.cfg | 69 - setup.py | 29 - test-requirements.txt | 26 - tools/tox_install.sh | 30 - tox.ini | 74 -- 292 files changed, 14 insertions(+), 38833 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .mailmap delete mode 100644 .testr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE create mode 100644 README delete mode 100644 README.rst delete mode 100644 babel.cfg delete mode 100644 bindep.txt delete mode 100644 doc/.gitignore delete mode 100644 doc/Makefile delete mode 100644 doc/source/conf.py delete mode 100644 doc/source/history.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/using-api-v2.rst delete mode 100644 doc/source/using-api-v3.rst delete mode 100644 doc/source/using-sessions.rst delete mode 100644 examples/pki/certs/cacert.pem delete mode 100644 examples/pki/certs/middleware.pem delete mode 100644 examples/pki/certs/signing_cert.pem delete mode 100644 examples/pki/certs/ssl_cert.pem delete mode 100644 examples/pki/cms/auth_token_revoked.json delete mode 100644 examples/pki/cms/auth_token_revoked.pem delete mode 100644 examples/pki/cms/auth_token_revoked.pkiz delete mode 100644 examples/pki/cms/auth_token_scoped.json delete mode 100644 examples/pki/cms/auth_token_scoped.pem delete mode 100644 examples/pki/cms/auth_token_scoped.pkiz delete mode 100644 examples/pki/cms/auth_token_scoped_expired.json delete mode 100644 examples/pki/cms/auth_token_scoped_expired.pem delete mode 100644 examples/pki/cms/auth_token_scoped_expired.pkiz delete mode 100644 examples/pki/cms/auth_token_unscoped.json delete mode 100644 examples/pki/cms/auth_token_unscoped.pem delete mode 100644 examples/pki/cms/auth_token_unscoped.pkiz delete mode 100644 examples/pki/cms/auth_v3_token_revoked.json delete mode 100644 examples/pki/cms/auth_v3_token_revoked.pem delete mode 100644 examples/pki/cms/auth_v3_token_revoked.pkiz delete mode 100644 examples/pki/cms/auth_v3_token_scoped.json delete mode 100644 examples/pki/cms/auth_v3_token_scoped.pem delete mode 100644 examples/pki/cms/auth_v3_token_scoped.pkiz delete mode 100644 examples/pki/cms/revocation_list.der delete mode 100644 examples/pki/cms/revocation_list.json delete mode 100644 examples/pki/cms/revocation_list.pem delete mode 100644 examples/pki/cms/revocation_list.pkiz delete mode 100644 examples/pki/gen_cmsz.py delete mode 100755 examples/pki/gen_pki.sh delete mode 100644 examples/pki/private/cakey.pem delete mode 100644 examples/pki/private/signing_key.pem delete mode 100644 examples/pki/private/ssl_key.pem delete mode 100755 examples/pki/run_all.sh delete mode 100644 keystoneclient/__init__.py delete mode 100644 keystoneclient/_discover.py delete mode 100644 keystoneclient/access.py delete mode 100644 keystoneclient/adapter.py delete mode 100644 keystoneclient/auth/__init__.py delete mode 100644 keystoneclient/auth/base.py delete mode 100644 keystoneclient/auth/cli.py delete mode 100644 keystoneclient/auth/conf.py delete mode 100644 keystoneclient/auth/identity/__init__.py delete mode 100644 keystoneclient/auth/identity/access.py delete mode 100644 keystoneclient/auth/identity/base.py delete mode 100644 keystoneclient/auth/identity/generic/__init__.py delete mode 100644 keystoneclient/auth/identity/generic/base.py delete mode 100644 keystoneclient/auth/identity/generic/cli.py delete mode 100644 keystoneclient/auth/identity/generic/password.py delete mode 100644 keystoneclient/auth/identity/generic/token.py delete mode 100644 keystoneclient/auth/identity/v2.py delete mode 100644 keystoneclient/auth/identity/v3/__init__.py delete mode 100644 keystoneclient/auth/identity/v3/base.py delete mode 100644 keystoneclient/auth/identity/v3/federated.py delete mode 100644 keystoneclient/auth/identity/v3/password.py delete mode 100644 keystoneclient/auth/identity/v3/token.py delete mode 100644 keystoneclient/auth/token_endpoint.py delete mode 100644 keystoneclient/base.py delete mode 100644 keystoneclient/baseclient.py delete mode 100644 keystoneclient/client.py delete mode 100644 keystoneclient/common/__init__.py delete mode 100644 keystoneclient/common/cms.py delete mode 100644 keystoneclient/contrib/__init__.py delete mode 100644 keystoneclient/contrib/auth/__init__.py delete mode 100644 keystoneclient/contrib/auth/v3/__init__.py delete mode 100644 keystoneclient/contrib/auth/v3/oidc.py delete mode 100644 keystoneclient/contrib/auth/v3/saml2.py delete mode 100644 keystoneclient/contrib/ec2/__init__.py delete mode 100644 keystoneclient/contrib/ec2/utils.py delete mode 100644 keystoneclient/discover.py delete mode 100644 keystoneclient/exceptions.py delete mode 100644 keystoneclient/fixture/__init__.py delete mode 100644 keystoneclient/fixture/discovery.py delete mode 100644 keystoneclient/fixture/exception.py delete mode 100644 keystoneclient/fixture/v2.py delete mode 100644 keystoneclient/fixture/v3.py delete mode 100644 keystoneclient/generic/__init__.py delete mode 100644 keystoneclient/generic/client.py delete mode 100644 keystoneclient/httpclient.py delete mode 100644 keystoneclient/i18n.py delete mode 100644 keystoneclient/service_catalog.py delete mode 100644 keystoneclient/session.py delete mode 100644 keystoneclient/tests/__init__.py delete mode 100644 keystoneclient/tests/functional/__init__.py delete mode 100644 keystoneclient/tests/functional/base.py delete mode 100755 keystoneclient/tests/functional/hooks/post_test_hook.sh delete mode 100644 keystoneclient/tests/functional/test_access.py delete mode 100644 keystoneclient/tests/functional/test_base.py delete mode 100644 keystoneclient/tests/functional/v2_0/__init__.py delete mode 100644 keystoneclient/tests/functional/v3/__init__.py delete mode 100644 keystoneclient/tests/functional/v3/client_fixtures.py delete mode 100644 keystoneclient/tests/functional/v3/test_credentials.py delete mode 100644 keystoneclient/tests/functional/v3/test_domain_configs.py delete mode 100644 keystoneclient/tests/functional/v3/test_domains.py delete mode 100644 keystoneclient/tests/functional/v3/test_ec2.py delete mode 100644 keystoneclient/tests/functional/v3/test_endpoint_filters.py delete mode 100644 keystoneclient/tests/functional/v3/test_endpoint_groups.py delete mode 100644 keystoneclient/tests/functional/v3/test_endpoints.py delete mode 100644 keystoneclient/tests/functional/v3/test_federation.py delete mode 100644 keystoneclient/tests/functional/v3/test_groups.py delete mode 100644 keystoneclient/tests/functional/v3/test_implied_roles.py delete mode 100644 keystoneclient/tests/functional/v3/test_policies.py delete mode 100644 keystoneclient/tests/functional/v3/test_projects.py delete mode 100644 keystoneclient/tests/functional/v3/test_regions.py delete mode 100644 keystoneclient/tests/functional/v3/test_roles.py delete mode 100644 keystoneclient/tests/functional/v3/test_services.py delete mode 100644 keystoneclient/tests/functional/v3/test_users.py delete mode 100644 keystoneclient/tests/unit/__init__.py delete mode 100644 keystoneclient/tests/unit/apiclient/__init__.py delete mode 100644 keystoneclient/tests/unit/apiclient/test_exceptions.py delete mode 100644 keystoneclient/tests/unit/auth/__init__.py delete mode 100644 keystoneclient/tests/unit/auth/test_access.py delete mode 100644 keystoneclient/tests/unit/auth/test_auth.py delete mode 100644 keystoneclient/tests/unit/auth/test_cli.py delete mode 100644 keystoneclient/tests/unit/auth/test_conf.py delete mode 100644 keystoneclient/tests/unit/auth/test_default_cli.py delete mode 100644 keystoneclient/tests/unit/auth/test_identity_common.py delete mode 100644 keystoneclient/tests/unit/auth/test_identity_v2.py delete mode 100644 keystoneclient/tests/unit/auth/test_identity_v3.py delete mode 100644 keystoneclient/tests/unit/auth/test_identity_v3_federated.py delete mode 100644 keystoneclient/tests/unit/auth/test_loading.py delete mode 100644 keystoneclient/tests/unit/auth/test_password.py delete mode 100644 keystoneclient/tests/unit/auth/test_token.py delete mode 100644 keystoneclient/tests/unit/auth/test_token_endpoint.py delete mode 100644 keystoneclient/tests/unit/auth/utils.py delete mode 100644 keystoneclient/tests/unit/client_fixtures.py delete mode 100644 keystoneclient/tests/unit/generic/__init__.py delete mode 100644 keystoneclient/tests/unit/generic/test_client.py delete mode 100644 keystoneclient/tests/unit/test_base.py delete mode 100644 keystoneclient/tests/unit/test_cms.py delete mode 100644 keystoneclient/tests/unit/test_discovery.py delete mode 100644 keystoneclient/tests/unit/test_ec2utils.py delete mode 100644 keystoneclient/tests/unit/test_fixtures.py delete mode 100644 keystoneclient/tests/unit/test_http.py delete mode 100644 keystoneclient/tests/unit/test_https.py delete mode 100644 keystoneclient/tests/unit/test_keyring.py delete mode 100644 keystoneclient/tests/unit/test_session.py delete mode 100644 keystoneclient/tests/unit/test_utils.py delete mode 100644 keystoneclient/tests/unit/utils.py delete mode 100644 keystoneclient/tests/unit/v2_0/__init__.py delete mode 100644 keystoneclient/tests/unit/v2_0/client_fixtures.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_access.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_auth.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_certificates.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_client.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_discovery.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_ec2.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_endpoints.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_extensions.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_roles.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_service_catalog.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_services.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_tenants.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_tokens.py delete mode 100644 keystoneclient/tests/unit/v2_0/test_users.py delete mode 100644 keystoneclient/tests/unit/v2_0/utils.py delete mode 100644 keystoneclient/tests/unit/v3/__init__.py delete mode 100644 keystoneclient/tests/unit/v3/client_fixtures.py delete mode 100644 keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml delete mode 100644 keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml delete mode 100644 keystoneclient/tests/unit/v3/saml2_fixtures.py delete mode 100644 keystoneclient/tests/unit/v3/test_access.py delete mode 100644 keystoneclient/tests/unit/v3/test_auth.py delete mode 100644 keystoneclient/tests/unit/v3/test_auth_manager.py delete mode 100644 keystoneclient/tests/unit/v3/test_auth_oidc.py delete mode 100644 keystoneclient/tests/unit/v3/test_auth_saml2.py delete mode 100644 keystoneclient/tests/unit/v3/test_client.py delete mode 100644 keystoneclient/tests/unit/v3/test_credentials.py delete mode 100644 keystoneclient/tests/unit/v3/test_discover.py delete mode 100644 keystoneclient/tests/unit/v3/test_domain_configs.py delete mode 100644 keystoneclient/tests/unit/v3/test_domains.py delete mode 100644 keystoneclient/tests/unit/v3/test_ec2.py delete mode 100644 keystoneclient/tests/unit/v3/test_endpoint_filter.py delete mode 100644 keystoneclient/tests/unit/v3/test_endpoint_groups.py delete mode 100644 keystoneclient/tests/unit/v3/test_endpoint_policy.py delete mode 100644 keystoneclient/tests/unit/v3/test_endpoints.py delete mode 100644 keystoneclient/tests/unit/v3/test_federation.py delete mode 100644 keystoneclient/tests/unit/v3/test_groups.py delete mode 100644 keystoneclient/tests/unit/v3/test_oauth1.py delete mode 100644 keystoneclient/tests/unit/v3/test_policies.py delete mode 100644 keystoneclient/tests/unit/v3/test_projects.py delete mode 100644 keystoneclient/tests/unit/v3/test_regions.py delete mode 100644 keystoneclient/tests/unit/v3/test_role_assignments.py delete mode 100644 keystoneclient/tests/unit/v3/test_roles.py delete mode 100644 keystoneclient/tests/unit/v3/test_service_catalog.py delete mode 100644 keystoneclient/tests/unit/v3/test_services.py delete mode 100644 keystoneclient/tests/unit/v3/test_simple_cert.py delete mode 100644 keystoneclient/tests/unit/v3/test_tokens.py delete mode 100644 keystoneclient/tests/unit/v3/test_trusts.py delete mode 100644 keystoneclient/tests/unit/v3/test_users.py delete mode 100644 keystoneclient/tests/unit/v3/utils.py delete mode 100644 keystoneclient/utils.py delete mode 100644 keystoneclient/v2_0/__init__.py delete mode 100644 keystoneclient/v2_0/certificates.py delete mode 100644 keystoneclient/v2_0/client.py delete mode 100644 keystoneclient/v2_0/ec2.py delete mode 100644 keystoneclient/v2_0/endpoints.py delete mode 100644 keystoneclient/v2_0/extensions.py delete mode 100644 keystoneclient/v2_0/roles.py delete mode 100644 keystoneclient/v2_0/services.py delete mode 100644 keystoneclient/v2_0/tenants.py delete mode 100644 keystoneclient/v2_0/tokens.py delete mode 100644 keystoneclient/v2_0/users.py delete mode 100644 keystoneclient/v3/__init__.py delete mode 100644 keystoneclient/v3/auth.py delete mode 100644 keystoneclient/v3/client.py delete mode 100644 keystoneclient/v3/contrib/__init__.py delete mode 100644 keystoneclient/v3/contrib/endpoint_filter.py delete mode 100644 keystoneclient/v3/contrib/endpoint_policy.py delete mode 100644 keystoneclient/v3/contrib/federation/__init__.py delete mode 100644 keystoneclient/v3/contrib/federation/base.py delete mode 100644 keystoneclient/v3/contrib/federation/core.py delete mode 100644 keystoneclient/v3/contrib/federation/domains.py delete mode 100644 keystoneclient/v3/contrib/federation/identity_providers.py delete mode 100644 keystoneclient/v3/contrib/federation/mappings.py delete mode 100644 keystoneclient/v3/contrib/federation/projects.py delete mode 100644 keystoneclient/v3/contrib/federation/protocols.py delete mode 100644 keystoneclient/v3/contrib/federation/saml.py delete mode 100644 keystoneclient/v3/contrib/federation/service_providers.py delete mode 100644 keystoneclient/v3/contrib/oauth1/__init__.py delete mode 100644 keystoneclient/v3/contrib/oauth1/access_tokens.py delete mode 100644 keystoneclient/v3/contrib/oauth1/auth.py delete mode 100644 keystoneclient/v3/contrib/oauth1/consumers.py delete mode 100644 keystoneclient/v3/contrib/oauth1/core.py delete mode 100644 keystoneclient/v3/contrib/oauth1/request_tokens.py delete mode 100644 keystoneclient/v3/contrib/oauth1/utils.py delete mode 100644 keystoneclient/v3/contrib/simple_cert.py delete mode 100644 keystoneclient/v3/contrib/trusts.py delete mode 100644 keystoneclient/v3/credentials.py delete mode 100644 keystoneclient/v3/domain_configs.py delete mode 100644 keystoneclient/v3/domains.py delete mode 100644 keystoneclient/v3/ec2.py delete mode 100644 keystoneclient/v3/endpoint_groups.py delete mode 100644 keystoneclient/v3/endpoints.py delete mode 100644 keystoneclient/v3/groups.py delete mode 100644 keystoneclient/v3/policies.py delete mode 100644 keystoneclient/v3/projects.py delete mode 100644 keystoneclient/v3/regions.py delete mode 100644 keystoneclient/v3/role_assignments.py delete mode 100644 keystoneclient/v3/roles.py delete mode 100644 keystoneclient/v3/services.py delete mode 100644 keystoneclient/v3/tokens.py delete mode 100644 keystoneclient/v3/users.py delete mode 100644 releasenotes/notes/.placeholder delete mode 100644 releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml delete mode 100644 releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml delete mode 100644 releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml delete mode 100644 releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml delete mode 100644 releasenotes/notes/bug-1641674-4862454115265e76.yaml delete mode 100644 releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml delete mode 100644 releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml delete mode 100644 releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml delete mode 100644 releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml delete mode 100644 releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml delete mode 100644 releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml delete mode 100644 releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml delete mode 100644 releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml delete mode 100644 releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml delete mode 100644 releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml delete mode 100644 releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/_templates/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/mitaka.rst delete mode 100644 releasenotes/source/newton.rst delete mode 100644 releasenotes/source/ocata.rst delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100755 tools/tox_install.sh delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 2f17ab1b..00000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = keystoneclient -omit = keystoneclient/tests/* - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6b6f10de..00000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -.coverage -.testrepository -subunit.log -.venv -*,cover -cover -*.pyc -.idea -*.sw? -*.egg -*~ -.tox -AUTHORS -ChangeLog -build -dist -python_keystoneclient.egg-info -keystoneclient/versioninfo -doc/source/api -# Development environment files -.project -.pydevproject -# Temporary files created during test, but not removed -examples/pki/certs/tmp* -# Files created by releasenotes build -releasenotes/build diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 56224f5d..00000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/python-keystoneclient.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index c804401b..00000000 --- a/.mailmap +++ /dev/null @@ -1,6 +0,0 @@ -# Format is: -# -# - - - diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 3d3e1e6e..00000000 --- a/.testr.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -test_command=${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystoneclient/tests/unit} $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 604d3ac7..00000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,18 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps documented at: - - https://docs.openstack.org/infra/manual/developers.html - -If you already have a good understanding of how the system works -and your OpenStack accounts are set up, you can skip to the -development workflow section of this documentation to learn how -changes to OpenStack should be submitted for review via the -Gerrit tool: - - https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/python-keystoneclient diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 6ea94ff6..00000000 --- a/HACKING.rst +++ /dev/null @@ -1,24 +0,0 @@ -Keystone Style Commandments -=========================== - -- Step 1: Read the OpenStack Style Commandments - https://docs.openstack.org/hacking/latest/ -- Step 2: Read on - -Exceptions ----------- - -When dealing with exceptions from underlying libraries, translate those -exceptions to an instance or subclass of ClientException. - -======= -Testing -======= - -python-keystoneclient uses testtools and testr for its unittest suite -and its test runner. Basic workflow around our use of tox and testr can -be found at https://wiki.openstack.org/testr. If you'd like to learn more -in depth: - - https://testtools.readthedocs.org/ - https://testrepository.readthedocs.org/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 32b66114..00000000 --- a/LICENSE +++ /dev/null @@ -1,209 +0,0 @@ -Copyright (c) 2009 Jacob Kaplan-Moss - initial codebase (< v2.1) -Copyright (c) 2011 Rackspace - OpenStack extensions (>= v2.1) -Copyright (c) 2011 Nebula, Inc - Keystone refactor (>= v2.7) -All rights reserved. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README new file mode 100644 index 00000000..8fcd2b2f --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index 33edffb7..00000000 --- a/README.rst +++ /dev/null @@ -1,64 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: https://governance.openstack.org/badges/python-keystoneclient.svg - :target: https://governance.openstack.org/reference/tags/index.html - -.. Change things from this point on - -Python bindings to the OpenStack Identity API (Keystone) -======================================================== - -.. image:: https://img.shields.io/pypi/v/python-keystoneclient.svg - :target: https://pypi.python.org/pypi/python-keystoneclient/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/python-keystoneclient.svg - :target: https://pypi.python.org/pypi/python-keystoneclient/ - :alt: Downloads - -This is a client for the OpenStack Identity API, implemented by the Keystone -team; it contains a Python API (the ``keystoneclient`` module) for -OpenStack's Identity Service. For command line interface support, use -`OpenStackClient`_. - -* `PyPi`_ - package installation -* `Online Documentation`_ -* `Launchpad project`_ - release management -* `Blueprints`_ - feature specifications -* `Bugs`_ - issue tracking -* `Source`_ -* `Specs`_ -* `How to Contribute`_ - -.. _PyPi: https://pypi.python.org/pypi/python-keystoneclient -.. _Online Documentation: https://docs.openstack.org/python-keystoneclient/latest/ -.. _Launchpad project: https://launchpad.net/python-keystoneclient -.. _Blueprints: https://blueprints.launchpad.net/python-keystoneclient -.. _Bugs: https://bugs.launchpad.net/python-keystoneclient -.. _Source: https://git.openstack.org/cgit/openstack/python-keystoneclient -.. _OpenStackClient: https://pypi.python.org/pypi/python-openstackclient -.. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html -.. _Specs: https://specs.openstack.org/openstack/keystone-specs/ - -.. contents:: Contents: - :local: - -Python API ----------- - -By way of a quick-start:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - >>> auth = v3.Password(auth_url="http://example.com:5000/v3", username="admin", - ... password="password", project_name="admin", - ... user_domain_id="default", project_domain_id="default") - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.projects.list() - [...] - >>> project = keystone.projects.create(name="test", description="My new Project!", domain="default", enabled=True) - >>> project.delete() diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab81..00000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index d1793694..00000000 --- a/bindep.txt +++ /dev/null @@ -1,23 +0,0 @@ -# This is a cross-platform list tracking distribution packages needed by tests; -# see https://docs.openstack.org/infra/bindep/ for additional information. - -gettext -libssl-dev - -dbus-devel [platform:rpm] -dbus-glib-devel [platform:rpm] -libdbus-1-dev [platform:dpkg] -libdbus-glib-1-dev [platform:dpkg] -libffi-dev [platform:dpkg] -libffi-devel [platform:rpm] -libsasl2-dev [platform:dpkg] -libxml2-dev [platform:dpkg] -libxslt1-dev [platform:dpkg] -python-all-dev [platform:dpkg] -python3-all-dev [platform:dpkg] - -cyrus-sasl-devel [platform:rpm] -libxml2-devel [platform:rpm] -python-devel [platform:rpm] -python3-devel [platform:fedora] -python34-devel [platform:centos] diff --git a/doc/.gitignore b/doc/.gitignore deleted file mode 100644 index 567609b1..00000000 --- a/doc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 430e5a33..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,90 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXSOURCE = source -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SPHINXSOURCE) - -.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-keystoneclient.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-keystoneclient.qhc" - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ - "run these through (pdf)latex." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 56363055..00000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,232 +0,0 @@ -# python-keystoneclient documentation build configuration file, created by -# sphinx-quickstart on Sun Dec 6 14:19:25 2009. -# -# This file is execfile()d with the current directory set to its containing -# dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -from __future__ import unicode_literals - -import os -import sys - -import pbr.version - - -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), - '..', '..'))) - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) - -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.intersphinx', - 'openstackdocstheme', - ] - -todo_include_todos = True - -# Add any paths that contain templates here, relative to this directory. -# templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'python-keystoneclient' -copyright = 'OpenStack Contributors' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -version_info = pbr.version.VersionInfo('python-keystoneclient') -# The short X.Y version. -version = version_info.version_string() -# The full version, including alpha/beta/rc tags. -release = version_info.release_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of documents that shouldn't be included in the build. -#unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['keystoneclient.'] - -# Grouping the document tree for man pages. -# List of tuples 'sourcefile', 'target', 'title', 'Authors name', 'manual' - -#man_pages = [] - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -#html_theme_path = ["."] -#html_theme = '_theme' -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_use_modindex = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'python-keystoneclientdoc' - - -# -- Options for LaTeX output ------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]) -# . -latex_documents = [ - ('index', 'python-keystoneclient.tex', - 'python-keystoneclient Documentation', - 'Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss', - 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_use_modindex = True - -keystoneauth_url = 'https://docs.openstack.org/keystoneauth/latest/' -intersphinx_mapping = { - 'python': ('https://docs.python.org/', None), - 'osloconfig': ('https://docs.openstack.org/oslo.config/latest/', None), - 'keystoneauth1': (keystoneauth_url, None), -} - -# -- Options for openstackdocstheme ------------------------------------------- -repository_name = 'openstack/python-keystoneclient' -bug_project = 'python-keystoneclient' -bug_tag = '' diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 69ed4fe6..00000000 --- a/doc/source/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index bee96306..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,54 +0,0 @@ -Python bindings to the OpenStack Identity API (Keystone) -======================================================== - -This is a client for OpenStack Identity API. There's a Python API for -:doc:`Identity API v3 ` and :doc:`v2 ` (the -:mod:`keystoneclient` modules). - -Contents: - -.. toctree:: - :maxdepth: 1 - - using-api-v3 - using-sessions - using-api-v2 - api/modules - -Related Identity Projects -========================= - -In addition to creating the Python client library, the Keystone team also -provides `Identity Service`_, as well as `WSGI Middleware`_. - -.. _`Identity Service`: https://docs.openstack.org/keystone/latest/ -.. _`WSGI Middleware`: https://docs.openstack.org/keystonemiddleware/latest/ - -Release Notes -============= - -.. toctree:: - :maxdepth: 1 - - history - -Contributing -============ - -Code is hosted `on GitHub`_. Submit bugs to the Keystone project on -`Launchpad`_. Submit code to the ``openstack/python-keystoneclient`` project -using `Gerrit`_. - -.. _on GitHub: https://github.com/openstack/python-keystoneclient -.. _Launchpad: https://launchpad.net/python-keystoneclient -.. _Gerrit: https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Run tests with ``tox``. - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/using-api-v2.rst b/doc/source/using-api-v2.rst deleted file mode 100644 index 1b7c5dea..00000000 --- a/doc/source/using-api-v2.rst +++ /dev/null @@ -1,125 +0,0 @@ -======================= -Using the V2 client API -======================= - -Introduction -============ - -The main concepts in the Identity v2 API are: - - * tenants - * users - * roles - * services - * endpoints - -The V2 client API lets you query and make changes through -managers. For example, to manipulate tenants, you interact with a -``keystoneclient.v2_0.tenants.TenantManager`` object. - -You obtain access to managers via attributes of the -``keystoneclient.v2_0.client.Client`` object. For example, the ``tenants`` -attribute of the ``Client`` class is a tenant manager:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> keystone.tenants.list() # List tenants - -You create a valid ``keystoneclient.v2_0.client.Client`` object by passing -a :class:`~keystoneauth1.session.Session` to the constructor. Authentication -and examples of common tasks are provided below. - -You can generally expect that when the client needs to propagate an exception -it will raise an instance of subclass of -``keystoneclient.exceptions.ClientException`` - -Authenticating -============== - -There are two ways to authenticate against keystone: - * against the admin endpoint with the admin token - * against the public endpoint with a username and password - -If you are an administrator, you can authenticate by connecting to the admin -endpoint and using the admin token (sometimes referred to as the service -token). The token is specified as the ``admin_token`` configuration option in -your keystone.conf config file, which is typically in /etc/keystone:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> token = '012345SECRET99TOKEN012345' - >>> endpoint = 'http://192.168.206.130:35357/v2.0' - >>> auth = v2.Token(auth_url=endpoint, token=token) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - -If you have a username and password, authentication is done against the -public endpoint. You must also specify a tenant that is associated with the -user:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> username='adminUser' - >>> password='secretword' - >>> tenant_name='openstackDemo' - >>> auth_url='http://192.168.206.130:5000/v2.0' - >>> auth = v2.Password(username=username, password=password, - ... tenant_name=tenant_name, auth_url=auth_url) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - -Creating tenants -================ - -This example will create a tenant named *openstackDemo*:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> keystone.tenants.create(tenant_name="openstackDemo", - ... description="Default Tenant", enabled=True) - - -Creating users -============== - -This example will create a user named *adminUser* with a password *secretword* -in the openstackDemo tenant. We first need to retrieve the tenant:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> tenants = keystone.tenants.list() - >>> my_tenant = [x for x in tenants if x.name=='openstackDemo'][0] - >>> my_user = keystone.users.create(name="adminUser", - ... password="secretword", - ... tenant_id=my_tenant.id) - -Creating roles and adding users -=============================== - -This example will create an admin role and add the *my_user* user to that -role, but only for the *my_tenant* tenant: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> role = keystone.roles.create('admin') - >>> my_tenant = ... - >>> my_user = ... - >>> keystone.roles.add_user_role(my_user, role, my_tenant) - -Creating services and endpoints -=============================== - -This example will create the service and corresponding endpoint for the -Compute service:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> service = keystone.services.create(name="nova", service_type="compute", - ... description="Nova Compute Service") - >>> keystone.endpoints.create( - ... region="RegionOne", service_id=service.id, - ... publicurl="http://192.168.206.130:8774/v2/%(tenant_id)s", - ... adminurl="http://192.168.206.130:8774/v2/%(tenant_id)s", - ... internalurl="http://192.168.206.130:8774/v2/%(tenant_id)s") diff --git a/doc/source/using-api-v3.rst b/doc/source/using-api-v3.rst deleted file mode 100644 index f0c82c5f..00000000 --- a/doc/source/using-api-v3.rst +++ /dev/null @@ -1,140 +0,0 @@ -======================= -Using the V3 Client API -======================= - -Introduction -============ - -The main concepts in the Identity v3 API are: - - * :py:mod:`~keystoneclient.v3.credentials` - * :py:mod:`~keystoneclient.v3.domain_configs` - * :py:mod:`~keystoneclient.v3.domains` - * :py:mod:`~keystoneclient.v3.endpoints` - * :py:mod:`~keystoneclient.v3.groups` - * :py:mod:`~keystoneclient.v3.policies` - * :py:mod:`~keystoneclient.v3.projects` - * :py:mod:`~keystoneclient.v3.regions` - * :py:mod:`~keystoneclient.v3.role_assignments` - * :py:mod:`~keystoneclient.v3.roles` - * :py:mod:`~keystoneclient.v3.services` - * :py:mod:`~keystoneclient.v3.tokens` - * :py:mod:`~keystoneclient.v3.users` - -The :py:mod:`keystoneclient.v3.client` API lets you query and make changes -through ``managers``. For example, to manipulate a project (formerly -called tenant), you interact with a -:py:class:`keystoneclient.v3.projects.ProjectManager` object. - -You obtain access to managers through attributes of a -:py:class:`keystoneclient.v3.client.Client` object. For example, the -``projects`` attribute of a ``Client`` object is a projects manager:: - - >>> from keystoneclient.v3 import client - >>> keystone = client.Client(...) - >>> keystone.projects.list() # List projects - -While it is possible to instantiate a -:py:class:`keystoneclient.v3.client.Client` object (as done above for -clarity), the recommended approach is to use the discovery mechanism -provided by the :py:class:`keystoneclient.client.Client` class. The -appropriate class will be instantiated depending on the API versions -available:: - - >>> from keystoneclient import client - >>> keystone = - ... client.Client(auth_url='http://localhost:5000', ...) - >>> type(keystone) - - -One can force the use of a specific version of the API, either by -using the ``version`` keyword argument:: - - >>> from keystoneclient import client - >>> keystone = client.Client(auth_url='http://localhost:5000', - version=(2,), ...) - >>> type(keystone) - - >>> keystone = client.Client(auth_url='http://localhost:5000', - version=(3,), ...) - >>> type(keystone) - - -Or by specifying directly the specific API version authentication URL -as the auth_url keyword argument:: - - >>> from keystoneclient import client - >>> keystone = - ... client.Client(auth_url='http://localhost:5000/v2.0', ...) - >>> type(keystone) - - >>> keystone = - ... client.Client(auth_url='http://localhost:5000/v3', ...) - >>> type(keystone) - - -Upon successful authentication, a :py:class:`keystoneclient.v3.client.Client` -object is returned (when using the Identity v3 API). Authentication and -examples of common tasks are provided below. - -You can generally expect that when the client needs to propagate an -exception it will raise an instance of subclass of -:class:`keystoneclient.exceptions.ClientException`. - -Authenticating Using Sessions -============================= - -Instantiate a :py:class:`keystoneclient.v3.client.Client` using a -:py:class:`~keystoneauth1.session.Session` to provide the authentication -plugin, SSL/TLS certificates, and other data:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - >>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v3', - ... user_id='myuserid', - ... password='mypassword', - ... project_id='myprojectid') - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - -For more information on Sessions refer to: `Using Sessions`_. - -.. _`Using Sessions`: using-sessions.html - -Non-Session Authentication (deprecated) -======================================= - -The *deprecated* way to authenticate is to pass the username, the user's domain -name (which will default to 'Default' if it is not specified), and a -password:: - - >>> from keystoneclient import client - >>> auth_url = 'http://localhost:5000' - >>> username = 'adminUser' - >>> user_domain_name = 'Default' - >>> password = 'secreetword' - >>> keystone = client.Client(auth_url=auth_url, version=(3,), - ... username=username, password=password, - ... user_domain_name=user_domain_name) - -A :py:class:`~keystoneauth1.session.Session` should be passed to the Client -instead. Using a Session you're not limited to authentication using a username -and password but can take advantage of other more secure authentication -methods. - -You may optionally specify a domain or project (along with its project -domain name), to obtain a scoped token:: - - >>> from keystoneclient import client - >>> auth_url = 'http://localhost:5000' - >>> username = 'adminUser' - >>> user_domain_name = 'Default' - >>> project_name = 'demo' - >>> project_domain_name = 'Default' - >>> password = 'secreetword' - >>> keystone = client.Client(auth_url=auth_url, version=(3,), - ... username=username, password=password, - ... user_domain_name=user_domain_name, - ... project_name=project_name, - ... project_domain_name=project_domain_name) diff --git a/doc/source/using-sessions.rst b/doc/source/using-sessions.rst deleted file mode 100644 index a5a5a58d..00000000 --- a/doc/source/using-sessions.rst +++ /dev/null @@ -1,200 +0,0 @@ -============== -Using Sessions -============== - -Introduction -============ - -The :py:class:`keystoneauth1.session.Session` class was introduced into -keystoneclient as an attempt to bring a unified interface to the various -OpenStack clients that share common authentication and request parameters -between a variety of services. - -The model for using a Session and auth plugin as well as the general terms used -have been heavily inspired by the `requests `_ -library. However neither the Session class nor any of the authentication -plugins rely directly on those concepts from the requests library so you should -not expect a direct translation. - -Features --------- - -- Common client authentication - - Authentication is handled by one of a variety of authentication plugins and - then this authentication information is shared between all the services that - use the same Session object. - -- Security maintenance - - Security code is maintained in a single place and reused between all - clients such that in the event of problems it can be fixed in a single - location. - -- Standard discovery mechanisms - - Clients are not expected to have any knowledge of an identity token or any - other form of identification credential. Service and endpoint discovery are - handled by the Session and plugins. - - -Sessions for Users -================== - -The Session object is the contact point to your OpenStack cloud services. It -stores the authentication credentials and connection information required to -communicate with OpenStack such that it can be reused to communicate with many -services. When creating services this Session object is passed to the client -so that it may use this information. - -A Session will authenticate on demand. When a request that requires -authentication passes through the Session the authentication plugin will be -asked for a valid token. If a valid token is available it will be used -otherwise the authentication plugin may attempt to contact the authentication -service and fetch a new one. - -An example from keystoneclient:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - - >>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v3', - ... username='myuser', - ... password='mypassword', - ... project_id='proj', - ... user_domain_id='domain') - >>> sess = session.Session(auth=auth, - ... verify='/path/to/ca.cert') - >>> ks = client.Client(session=sess) - >>> users = ks.users.list() - -As clients adopt this means of operating they will be created in a similar -fashion by passing the Session object to the client's constructor. - - -Migrating keystoneclient to use a Session ------------------------------------------ - -By using a session with a keystoneclient Client we presume that you have opted -in to new behavior defined by the session. For example authentication is now -on-demand rather than on creation. To allow this change in behavior there are -a number of functions that have changed behavior or are no longer available. - -For example the -:py:meth:`keystoneclient.httpclient.HTTPClient.authenticate` method used -to be able to always re-authenticate the current client and fetch a new token. -As this is now controlled by the Session and not the client this has changed, -however the function will still exist to provide compatibility with older -clients. - -Likewise certain parameters such as ``user_id`` and ``auth_token`` that used to -be available on the client object post authentication will remain -uninitialized. - -When converting an application to use a session object with keystoneclient you -should be aware of the possibility of changes to authentication and -authentication parameters and make sure to test your code thoroughly. It should -have no impact on the typical CRUD interaction with the client. - - -Sharing Authentication Plugins ------------------------------- - -A session can only contain one authentication plugin however there is nothing -that specifically binds the authentication plugin to that session, a new -Session can be created that reuses the existing authentication plugin:: - - >>> new_sess = session.Session(auth=sess.auth, - verify='/path/to/different-cas.cert') - -In this case we cannot know which session object will be used when the plugin -performs the authentication call so the command must be able to succeed with -either. - -Authentication plugins can also be provided on a per-request basis. This will -be beneficial in a situation where a single session is juggling multiple -authentication credentials:: - - >>> sess.get('https://my.keystone.com:5000/v3', - auth=my_auth_plugin) - -If an auth plugin is provided via parameter then it will override any auth -plugin on the session. - -Sessions for Client Developers -============================== - -Sessions are intended to take away much of the hassle of dealing with -authentication data and token formats. Clients should be able to specify filter -parameters for selecting the endpoint and have the parsing of the catalog -managed for them. - -Authentication --------------- - -When making a request with a session object you can simply pass the keyword -parameter ``authenticated`` to indicate whether the argument should contain a -token, by default a token is included if an authentication plugin is available:: - - >>> # In keystone this route is unprotected by default - >>> resp = sess.get('https://my.keystone.com:5000/v3', - authenticated=False) - - -Service Discovery ------------------ - -In OpenStack the URLs of available services are distributed to the user as a -part of the token they receive called the Service Catalog. Clients are expected -to use the URLs from the Service Catalog rather than have them provided. - -In general a client does not need to know the full URL for the server that they -are communicating with, simply that it should send a request to a path -belonging to the correct service. - -This is controlled by the ``endpoint_filter`` parameter to a request which -contains all the information an authentication plugin requires to determine the -correct URL to which to send a request. When using this mode only the path for -the request needs to be specified:: - - >>> resp = session.get('/v3/users', - endpoint_filter={'service_type': 'identity', - 'interface': 'public', - 'region_name': 'myregion'}) - -``endpoint_filter`` accepts a number of arguments with which it can determine -an endpoint url: - -- ``service_type``: the type of service. For example ``identity``, ``compute``, - ``volume`` or many other predefined identifiers. - -- ``interface``: the network exposure the interface has. This will be one of: - - - ``public``: An endpoint that is available to the wider internet or network. - - ``internal``: An endpoint that is only accessible within the private network. - - ``admin``: An endpoint to be used for administrative tasks. - -- ``region_name``: the name of the region where the endpoint resides. - -The endpoint filter is a simple key-value filter and can be provided with any -number of arguments. It is then up to the auth plugin to correctly use the -parameters it understands. - -The session object determines the URL matching the filter and append to it the -provided path and so create a valid request. If multiple URL matches are found -then any one may be chosen. - -While authentication plugins will endeavour to maintain a consistent set of -arguments for an ``endpoint_filter`` the concept of an authentication plugin is -purposefully generic and a specific mechanism may not know how to interpret -certain arguments and ignore them. For example the -:py:class:`keystoneauth1.identity.generic.token.Token` plugin (which is used -when you want to always use a specific endpoint and token combination) will -always return the same endpoint regardless of the parameters to -``endpoint_filter`` or a custom OpenStack authentication mechanism may not have -the concept of multiple ``interface`` options and choose to ignore that -parameter. - -There is some expectation on the user that they understand the limitations of -the authentication system they are using. diff --git a/examples/pki/certs/cacert.pem b/examples/pki/certs/cacert.pem deleted file mode 100644 index 952bdaea..00000000 --- a/examples/pki/certs/cacert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID1jCCAr6gAwIBAgIJAJOtRP2+wrM/MA0GCSqGSIb3DQEBBQUAMIGeMQowCAYD -VQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55 -dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMG -CSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2Vs -ZiBTaWduZWQwIBcNMTMwOTEzMTYyNTQyWhgPMjA3MjAzMDcxNjI1NDJaMIGeMQow -CAYDVQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1 -bm55dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTEl -MCMGCSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxML -U2VsZiBTaWduZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCl8906 -EaRpibQFcCBWfxzLi5x/XpZ9iL6UX92NrSJxcDbaGws7s+GtjgDy8UOEonesRWTe -qQEZtHpC3/UHHOnsA8F6ha/pq9LioqT7RehCnZCLBJwh5Ct+lclpWs15SkjJD2LT -Dkjox0eA9nOBx+XDlWyU/GAyqx5Wsvg/Kxr0iod9/4IcJdnSdUjq4v0Cxg/zNk08 -XPJX+F0bUDhgdUf7JrAmmS5LA8wphRnbIgtVsf6VN9HrbqtHAJDxh8gEfuwdhEW1 -df1fBtZ+6WMIF3IRSbIsZELFB6sqcyRj7HhMoWMkdEyPb2f8mq61MzTgE6lJGIyT -RvEoFie7qtGADIofAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEFBQADggEBAJRMdEwAdN+crqI9dBLYlbBbnQ8xr9mk+REMdz9+SKhDCNdVisWU -iLEZvK/aozrsRsDi81JjS4Tz0wXo8zsPPoDnXgDYEicNPTKifbPKgHdDIGFOwBKn -y2cF6fHEn8n3KIBrDCNY6rHcYGZ7lbq/8eF0GoYQboPiuYesvVpynPmIK5/Mmire -EuuZALAe1IFqqFt+l6tiJU2JWUFjLkFARMOD14qFZm+SInl64toi08j6gdou+NMW -7GEMbVHwNTafM/TgFN5j0yP9SAnYubckLSyH6hwR+rM8dztP5769joxQfnc9O/Bn -TBD9KFpeQv6VJWLAxiIKcQCRTTDJLZZ0MQI= ------END CERTIFICATE----- diff --git a/examples/pki/certs/middleware.pem b/examples/pki/certs/middleware.pem deleted file mode 100644 index 7d593efd..00000000 --- a/examples/pki/certs/middleware.pem +++ /dev/null @@ -1,50 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpjCCAo4CARAwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK -EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr -ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x -MzA5MTMxNjI1NDNaGA8yMDcyMDMwNzE2MjU0M1owgZAxCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh -Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv -cGVuc3RhY2sub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDL06AaJROwHPgJ9tcySSBepzJ81jYars2sMvLjyuvd -iIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rpv8dGDIDsxZQVjT/4SLaQUOeDM+9b -fkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLYWso0SJD0vAi1gmGDlSM/mmhhHTpC -DGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1ZrslPC5lFvlHD7KBBf6IU2A8Xh/dUa3 -p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYRR45pPCVkk6vFsy6P0JwwpnkszB+L -cK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4YEPirGGrAgMBAAEwDQYJKoZIhvcN -AQEFBQADggEBAAjU7YomUx/U56p1KWHvr1B7oczHF8fPHYbuk5c/N81WOJeSRy+P -5ZGZ2UPjvqqXByv+78YWMKGY1BZ/2doeWuydr0sdSxEwmIUBYxFpujuYY+0AjS/n -mMr1ZijK7TJssteKM7/MClzghUhPweDZrAg3ff1hbhK5QSy+9UPxUqLH44tfYSVC -/BzM6se0p5ToM0bwdsa8TofaBRE1L1IW/Hg4VIGOoKs0R0uLm7+Oot2me2cEuZ6h -Wls6MED8ND1Nz8EAKwndkeDu2iMM+qx/YFp6K8BQ5E5nXd2rbUZUlQMp1WbUlZ87 -KvC98aT0UYIq6uo1Lx/dQvJs7faAkYd4lmE= ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL06AaJROwHPgJ -9tcySSBepzJ81jYars2sMvLjyuvdiIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rp -v8dGDIDsxZQVjT/4SLaQUOeDM+9bfkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLY -Wso0SJD0vAi1gmGDlSM/mmhhHTpCDGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1Zrs -lPC5lFvlHD7KBBf6IU2A8Xh/dUa3p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYR -R45pPCVkk6vFsy6P0JwwpnkszB+LcK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4 -YEPirGGrAgMBAAECggEATwvbY0hNwlb5uqOIAXBqpUqiQdexU9fG26lGmSDxKBDv -9o5frcRgBDrMWwvDCgY+HT4CAvB9kJx4/qnpVjkzJp/ZNiJ5VIiehIlbv348rXbh -xkk+bz5dDATCFOXuu1fwL2FhyM5anwhMAav0DyK1VLQ3jGzr9GO6L8hqAn+bQFFu -6ngiODwfhBMl5aRoL9UOBEhccK07znrH0JGRz+3+5Cdz59Xw91Bv210LhNNDL58+ -0JD0N+YztVOQd2bgwo0bQbOEijzmYq+0mjoqAnJh1/++y7PlIPs0AnPgqSnFPx9+ -6FsQEVRgk5Uq3kvPLaP4nT2y6MDZSp+ujYldvJhyQQKBgQDuX2pZIJMZ4aFnkG+K -TmJ5wsLa/u9an0TmvAL9RLtBpVpQNKD8cQ+y8PUZavXDbAIt5NWqZVnTbCR79Dnd -mZKblwcHhtsyA5f89el5KcxY2BREWdHdTnJpNd7XRlUECmzvX1zGj77lA982PhII -yflRBRV3vqLkgC8vfoYgRyRElwKBgQDa5jnLdx/RahfYMOgn1HE5o4hMzLR4Y0Dd -+gELshcUbPqouoP5zOb8WOagVJIgZVOSN+/VqbilVYrqRiNTn2rnoxs+HHRdaJNN -3eXllD4J2HfC2BIj1xSpIdyh2XewAJqw9IToHNB29QUhxOtgwseHciPG6JaKH2ik -kqGKH/EKDQKBgFFAftygiOPCkCTgC9UmANUmOQsy6N2H+pF3tsEj43xt44oBVnqW -A1boYXNnjRwuvdNs9BPf9i1l6E3EItFRXrLgWQoMwryakv0ryYh+YeRKyyW9RBbe -fYs1TJ8unx4Ae79gTxxztQsVNcmkgLs0NWKTjAzEE3w14V+cDhYEie1DAoGBAJdI -V5cLrBzBstsB6eBlDR9lqrRRIUS2a8U9m+1mVlcSfiWQSdehSd4K3tDdwePLw3ch -W4qR8n+pYAlLEe0gFvUhn5lMdwt7U5qUCeehjUKmrRYm2FqWsbu2IFJnBjXIJSC4 -zQXRrC0aZ0KQYpAL7XPpaVp1slyhGmPqxuO78Y0dAoGBAMHo3EIMwu9rfuGwFodr -GFsOZhfJqgo5GDNxxf89Q9WWpMDTCdX+wdBTrN/wsMbBuwIDHrUuRnk6D5CWRjSk -/ikCgHN3kOtrbL8zzqRomGAIIWKYGFEIGe1GHVGo5r//HXHdPxFXygvruQ/xbOA4 -RGvmDiji8vVDq7Shho8I6KuT ------END PRIVATE KEY----- diff --git a/examples/pki/certs/signing_cert.pem b/examples/pki/certs/signing_cert.pem deleted file mode 100644 index 63ab2478..00000000 --- a/examples/pki/certs/signing_cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpTCCAo0CAREwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK -EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr -ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x -MzA5MTMxNjI1NDNaGA8yMDcyMDMwNzE2MjU0M1owgY8xCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh -Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv -cGVuc3RhY2sub3JnMREwDwYDVQQDEwhLZXlzdG9uZTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAMz5WsgsuX3rZUdLwQpZXN2Ro7LQ6jEZnreBqMztVObw -BuC1WdiJsg6dVlC7PVdt+0gY1c8WFg1TKmsucxesQSyfGAPg+9T/hsRMb6y12uJx -fp3Wgqqw0U1HsXvMiaJH87MaGnt043BxzF+R9fhAcDk6Cyj5cx9J0LvZJEOzN4J4 -ZRyO6j/DZZItb3lK5W9xkuoT+mTdDZOQJnXyG818uiWfjdCkLjr1ruytRcBOo4na -Y828voT/A7I95+YCgKgbjiUWhHeTaNmMEQiGy0nGYfteC+oSsHOlxZ3b12azzHPk -83Bh2ez0Ih9vcZoe9DqvlFOXfv9q8OsYc5Yo6gPTXEsCAwEAATANBgkqhkiG9w0B -AQUFAAOCAQEAmaYE98kOQWu6DV84ZcZP/OdT8eeu3vdB247nRj+6+GYItN/Gzqt4 -HVvz7c+FVTolCcAQQ+z3XGswI9fIJ78Hb0p9CgnLprc3L7Xtk60Im59Xlf3tcurn -r/ZnSDcjRBXKiEDrSM0VrhAnc0GoSeb6aDWopec+1hWOWfBVAg9R8yJgU9sUgO3O -0gimGyrw8eubmNhckSQLJTunUTsrkcBjuSg63wAD9OqCiX6c2eoQr+0YBp2eV2/n -aOiJXWNLbeueMKSYiJNyyvM/dlON7/56cdwDTzKzgD34TImouM5VKipUwCX1ovLu -ITLzALzpqFFzc8ugV9pMgUKtDbZoPp9EEA== ------END CERTIFICATE----- diff --git a/examples/pki/certs/ssl_cert.pem b/examples/pki/certs/ssl_cert.pem deleted file mode 100644 index cdd2e4c0..00000000 --- a/examples/pki/certs/ssl_cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpjCCAo4CARAwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK -EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr -ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x -MzA5MTMxNjI1NDNaGA8yMDcyMDMwNzE2MjU0M1owgZAxCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh -Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv -cGVuc3RhY2sub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDL06AaJROwHPgJ9tcySSBepzJ81jYars2sMvLjyuvd -iIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rpv8dGDIDsxZQVjT/4SLaQUOeDM+9b -fkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLYWso0SJD0vAi1gmGDlSM/mmhhHTpC -DGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1ZrslPC5lFvlHD7KBBf6IU2A8Xh/dUa3 -p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYRR45pPCVkk6vFsy6P0JwwpnkszB+L -cK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4YEPirGGrAgMBAAEwDQYJKoZIhvcN -AQEFBQADggEBAAjU7YomUx/U56p1KWHvr1B7oczHF8fPHYbuk5c/N81WOJeSRy+P -5ZGZ2UPjvqqXByv+78YWMKGY1BZ/2doeWuydr0sdSxEwmIUBYxFpujuYY+0AjS/n -mMr1ZijK7TJssteKM7/MClzghUhPweDZrAg3ff1hbhK5QSy+9UPxUqLH44tfYSVC -/BzM6se0p5ToM0bwdsa8TofaBRE1L1IW/Hg4VIGOoKs0R0uLm7+Oot2me2cEuZ6h -Wls6MED8ND1Nz8EAKwndkeDu2iMM+qx/YFp6K8BQ5E5nXd2rbUZUlQMp1WbUlZ87 -KvC98aT0UYIq6uo1Lx/dQvJs7faAkYd4lmE= ------END CERTIFICATE----- diff --git a/examples/pki/cms/auth_token_revoked.json b/examples/pki/cms/auth_token_revoked.json deleted file mode 100644 index eab40a0b..00000000 --- a/examples/pki/cms/auth_token_revoked.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "access": { - "token": { - "expires": "2038-01-18T21:14:07Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "placeholder", - "tenant": { - "id": "tenant_id1", - "enabled": true, - "description": null, - "name": "tenant_name1" - } - }, - "serviceCatalog": [ - { - "endpoints_links": [], - "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" - } - ], - "type": "volume", - "name": "volume" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "image", - "name": "glance" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "compute", - "name": "nova" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "identity", - "name": "keystone" - } - ], - "user": { - "username": "revoked_username1", - "roles_links": [ - "role1", - "role2" - ], - "id": "revoked_user_id1", - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "name": "revoked_username1" - } - } -} diff --git a/examples/pki/cms/auth_token_revoked.pem b/examples/pki/cms/auth_token_revoked.pem deleted file mode 100644 index 12e4f0ce..00000000 --- a/examples/pki/cms/auth_token_revoked.pem +++ /dev/null @@ -1,79 +0,0 @@ ------BEGIN CMS----- -MIIOTQYJKoZIhvcNAQcCoIIOPjCCDjoCAQExCTAHBgUrDgMCGjCCDFoGCSqGSIb3 -DQEHAaCCDEsEggxHew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIwMzgtMDEtMThUMjE6MTQ6MDda -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogInBsYWNlaG9sZGVyIiwNCiAgICAgICAg -ICAgICJ0ZW5hbnQiOiB7DQogICAgICAgICAgICAgICAgImlkIjogInRlbmFudF9p -ZDEiLA0KICAgICAgICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAg -ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgICAgICJu -YW1lIjogInRlbmFudF9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAgICAgfSwN -CiAgICAgICAgInNlcnZpY2VDYXRhbG9nIjogWw0KICAgICAgICAgICAgew0KICAg -ICAgICAgICAgICAgICJlbmRwb2ludHNfbGlua3MiOiBbXSwNCiAgICAgICAgICAg -ICAgICAiZW5kcG9pbnRzIjogWw0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAu -MTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInB1YmxpY1VSTCI6ICJodHRwOi8v -MTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYx -N2EiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0K -ICAgICAgICAgICAgICAgICJ0eXBlIjogInZvbHVtZSIsDQogICAgICAgICAgICAg -ICAgIm5hbWUiOiAidm9sdW1lIg0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAg -IHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQogICAg -ICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6Ly8x -MjcuMC4wLjE6OTI5Mi92MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVn -aW9uIjogInJlZ2lvbk9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJwdWJsaWNVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5 -MjkyL3YxIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAg -XSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpbWFnZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAiZ2xhbmNlIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQog -ICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAg -ICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6 -Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6 -ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicHVibGlj -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQz -NWU4YTYwZmNmODliYjY2MTdhIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAg -ICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjb21wdXRl -IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJub3ZhIg0KICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xp -bmtzIjogW10sDQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAg -ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWlu -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMToz -NTM1Ny92Mi4wIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJwdWJsaWNVUkwi -OiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAiDQogICAgICAgICAgICAgICAg -ICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJ0eXBl -IjogImlkZW50aXR5IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJrZXlzdG9u -ZSINCiAgICAgICAgICAgIH0NCiAgICAgICAgXSwNCiAgICAgICAgInVzZXIiOiB7 -DQogICAgICAgICAgICAidXNlcm5hbWUiOiAicmV2b2tlZF91c2VybmFtZTEiLA0K -ICAgICAgICAgICAgInJvbGVzX2xpbmtzIjogWw0KICAgICAgICAgICAgICAgICJy -b2xlMSIsDQogICAgICAgICAgICAgICAgInJvbGUyIg0KICAgICAgICAgICAgXSwN -CiAgICAgICAgICAgICJpZCI6ICJyZXZva2VkX3VzZXJfaWQxIiwNCiAgICAgICAg -ICAgICJyb2xlcyI6IFsNCiAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAg -ICAgICAgICJpZCI6ICJmMDNmZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYzMSIs -DQogICAgICAgICAgICAgICAgICAgICJuYW1lIjogInJvbGUxIg0KICAgICAgICAg -ICAgICAgIH0sDQogICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAg -ICAiaWQiOiAiZjAzZmRhOGY4YTMyNDliMmE3MGZiMWYxNzZhN2I2MzEiLA0KICAg -ICAgICAgICAgICAgICAgICAibmFtZSI6ICJyb2xlMiINCiAgICAgICAgICAgICAg -ICB9DQogICAgICAgICAgICBdLA0KICAgICAgICAgICAgIm5hbWUiOiAicmV2b2tl -ZF91c2VybmFtZTEiDQogICAgICAgIH0NCiAgICB9DQp9DQoxggHKMIIBxgIBATCB -pDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYD -VQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5TdGFjazERMA8GA1UECxMIS2V5 -c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25lQG9wZW5zdGFjay5vcmcxFDAS -BgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIB -AA2C5qslA4D7vzbiPJ+PzI6CWKH4fxy2nl6wFneHRlzflRGVtbk7/gwVpgHvVH8+ -FvQEWeXiCvpXDcHUae0YsdB6aifDRkRctoBwWZkSIkLtdLjZTBrwoOBD2cWPTlr6 -gFPp0ARCKVP87YXiKHXStvivZDQFbnBrPTZbGwsCZFXzDYtVPkDvgWOIzHP+olB0 -k0wrFXdTQrr62GmkUdgmY31SBLAmPRlvbFBsdM8R62EVc9Mdk7A8Xenpib6+3hPV -7Jgj5IcC3WWtI1A/WOzuEepfW5AU3bcmsJ4UrsJdZLPYqxy/FS37s7oekBOfSR+Y -WSVmaaTY21X3kOqAQULJTDI= ------END CMS----- diff --git a/examples/pki/cms/auth_token_revoked.pkiz b/examples/pki/cms/auth_token_revoked.pkiz deleted file mode 100644 index aff7b74f..00000000 --- a/examples/pki/cms/auth_token_revoked.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylVkt3ozgT3etXzD6nTwBjJ17MQjyMRSzZYAxIOwMJIB524gePX_8Jk0xn0n2me77xxlCC4ureW1X69k38NNNC5A8db4ebbwAjhHaQ2k8HhrJrTKAT6wcRczxd1w1Jh47Z6h5caunuzUixbnFd10rJ0rev1hZFE2A45hLuRbBQzTRlT8-dnVGFlPEE5-tce0C1e90r_gXxQyrWjvGEyCxwX2joiHWYA8xhg3OpwVupXS-cDnuHlhiHhsiHfKXDnIVZsw_tMu7QDOmowwZWVx5sV56p-gZqwZqb0prDSZCjE9LtI9OHB-0mshacBdk1stwyHtckFkyzqHZGZJV_oYF9Aiy4BaS49svhi_tghJZYwwNTKVTKAm9vCcS9XA5bEdsqo2pxSRbzCxiC7w8ULCQ8rsomscprlAsk1lSOrHb-sm3ES4KXmh2p4hs0dLPImtdDMhBMTrmAVsTW_BjVbj8EhxgN3PM-mPq7orkh2i9dKTYO11VvdqRTmxWHF8GXCkgfK6sJbVc9lShnFVZYThUs497pSbBTqUcbVpFqbZQ55WLFSzKUD4jskinlFdyg6nbHguQYKdNNVO3ykYupxMJh3-0_ogADjP8fhSYDWrVHKvtbb5TvkCzdZp0_XrGHJrd96mq75umE9PSacPNKuJuTivassjntdz0gBpaZl2WEaxVVqLoO7Jxw2hLFzF98aVBHSOY2kVJekiV5iazysh9dGoVCHSA0ncbWbtS-mp-SQesBXiVME3yJ1yLh8u-qgX8p2xTzohv4-lACDFL8FyXAzzNr8u-RW3Rg7aGB3d8i7DNf-0DOmLLLwQBVFMaZbW9fqkUVXqhYGPwv6v9TwjHR0C-YJR-jckQH_ll7Z0B3wdtHhVhIYVw4oCKceFjCvV-uLVMB2GKc8XRKK6QQbk7oWJnvhKo3uHHl1_tgfvGU6bvEApHldwL5Cfi-jW81XmVSsoSzVffYYh4PKIR05mxtiCamzxW8VX9qdfArr_9KDfBv9vvjdu05uMkj-htbatfBOLE8P4n_t1sTXZyTQaVkWTbvKvFIkZskdP-yO_jwe1TNlSHjSh8b5l8Jx0QitiiioLx85Qx8JQ2LEiVeLLaDROxHRXZfFAGfJfmVIj9J3oBE9PZ9QH5VhTI2YCNqpRP3f7M9-D3fizlQu8dkWeRfrP8GWFj2iTW_MEHg-KLfsxC9z8Xh-vNAsUvRXN6G2ZiEYk68q_DRHMQY8_tQaY9RdR7nQ2d3kdJ-DJ7xOreTzxMMCJ8rkXIu2WIux4rffRpltxe-y1gWI8G0EVYuqJdVwly9mM7OlHI7I71oqnxRYS9WqJeIxorbr70xFr2ReeZHqd8G8VDOFTZIxSxTZTzLcI-kdYA66sWiPlDLhGVJJWwrmviPQ9YWk8nadaiWky_sdixkw8GiCCfficSC6JdQatN0-SRONlqbIg1AT9eOhq7V3HzCMLWgvDM1F2vEM1cYFuN9hnXfx63eQ1tLia_B1IMF0bCLGmBCaviOszSb0kuC6eU5ZGJ071qTQ2d8-ODpu3kjZoGXiEPHvjddDB9vifUWI7BV_Gk8ca-ilbe2B7mWFq9ZkVvzRtJ0xwwW1bl8Dokk2n3pWLdE_S1RN73GVdyChQG345ewp8ukjCya7pSyjiq_gOnwtdjStqc1bNAew--nM3E406Czg0ATZMAFn0pmu102GdE2eWhrLybzSqvOEc8n8LJlq0g9L06bbtIfD1acv21OyvLk6kb3Bp4QtCYpT6PzDLZP8n5Wwf1dc7w7blCXcsuzZEWPC3y_UFf1RZVbQ1XWj538TKM7PF89WkDG98-hu9laucfd3RVqao5fpSe-Wbjqw7qfxcfkGDMyu3cbVWXO9m55ThBaeQQnC1p6BKiBVOuHh24fsocHLV3fvzqlVlPJC-zjYfase-fr9IyuxdWfNefEhnpyj9y7N_rcsOeFaGOgxmdovBYUBqbjPhQPrSvL-LHbrifzqzQld_3GOLGNUt_Npe40zarJpFyJOb905oi60SsEslMv7oOYuA9v_Cl5aJhHZhMEX7B9-BPcjtMmMb4frf8Hm6bNOA== \ No newline at end of file diff --git a/examples/pki/cms/auth_token_scoped.json b/examples/pki/cms/auth_token_scoped.json deleted file mode 100644 index 4ea30169..00000000 --- a/examples/pki/cms/auth_token_scoped.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "access": { - "token": { - "expires": "2038-01-18T21:14:07Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "placeholder", - "tenant": { - "id": "tenant_id1", - "enabled": true, - "description": null, - "name": "tenant_name1" - } - }, - "serviceCatalog": [ - { - "endpoints_links": [], - "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" - } - ], - "type": "volume", - "name": "volume" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "image", - "name": "glance" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "compute", - "name": "nova" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "identity", - "name": "keystone" - } - ], - "user": { - "username": "user_name1", - "roles_links": [ - "role1", - "role2" - ], - "id": "user_id1", - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "name": "user_name1" - } - } -} diff --git a/examples/pki/cms/auth_token_scoped.pem b/examples/pki/cms/auth_token_scoped.pem deleted file mode 100644 index 8754a959..00000000 --- a/examples/pki/cms/auth_token_scoped.pem +++ /dev/null @@ -1,78 +0,0 @@ ------BEGIN CMS----- -MIIONwYJKoZIhvcNAQcCoIIOKDCCDiQCAQExCTAHBgUrDgMCGjCCDEQGCSqGSIb3 -DQEHAaCCDDUEggwxew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIwMzgtMDEtMThUMjE6MTQ6MDda -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogInBsYWNlaG9sZGVyIiwNCiAgICAgICAg -ICAgICJ0ZW5hbnQiOiB7DQogICAgICAgICAgICAgICAgImlkIjogInRlbmFudF9p -ZDEiLA0KICAgICAgICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAg -ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgICAgICJu -YW1lIjogInRlbmFudF9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAgICAgfSwN -CiAgICAgICAgInNlcnZpY2VDYXRhbG9nIjogWw0KICAgICAgICAgICAgew0KICAg -ICAgICAgICAgICAgICJlbmRwb2ludHNfbGlua3MiOiBbXSwNCiAgICAgICAgICAg -ICAgICAiZW5kcG9pbnRzIjogWw0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAu -MTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInB1YmxpY1VSTCI6ICJodHRwOi8v -MTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYx -N2EiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0K -ICAgICAgICAgICAgICAgICJ0eXBlIjogInZvbHVtZSIsDQogICAgICAgICAgICAg -ICAgIm5hbWUiOiAidm9sdW1lIg0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAg -IHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQogICAg -ICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6Ly8x -MjcuMC4wLjE6OTI5Mi92MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVn -aW9uIjogInJlZ2lvbk9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJwdWJsaWNVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5 -MjkyL3YxIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAg -XSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpbWFnZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAiZ2xhbmNlIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQog -ICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAg -ICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6 -Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6 -ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicHVibGlj -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQz -NWU4YTYwZmNmODliYjY2MTdhIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAg -ICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjb21wdXRl -IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJub3ZhIg0KICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xp -bmtzIjogW10sDQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAg -ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWlu -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMToz -NTM1Ny92Mi4wIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJwdWJsaWNVUkwi -OiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAiDQogICAgICAgICAgICAgICAg -ICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJ0eXBl -IjogImlkZW50aXR5IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJrZXlzdG9u -ZSINCiAgICAgICAgICAgIH0NCiAgICAgICAgXSwNCiAgICAgICAgInVzZXIiOiB7 -DQogICAgICAgICAgICAidXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsDQogICAgICAg -ICAgICAicm9sZXNfbGlua3MiOiBbDQogICAgICAgICAgICAgICAgInJvbGUxIiwN -CiAgICAgICAgICAgICAgICAicm9sZTIiDQogICAgICAgICAgICBdLA0KICAgICAg -ICAgICAgImlkIjogInVzZXJfaWQxIiwNCiAgICAgICAgICAgICJyb2xlcyI6IFsN -CiAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICJpZCI6ICJm -MDNmZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYzMSIsDQogICAgICAgICAgICAg -ICAgICAgICJuYW1lIjogInJvbGUxIg0KICAgICAgICAgICAgICAgIH0sDQogICAg -ICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAiaWQiOiAiZjAzZmRh -OGY4YTMyNDliMmE3MGZiMWYxNzZhN2I2MzEiLA0KICAgICAgICAgICAgICAgICAg -ICAibmFtZSI6ICJyb2xlMiINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAg -ICBdLA0KICAgICAgICAgICAgIm5hbWUiOiAidXNlcl9uYW1lMSINCiAgICAgICAg -fQ0KICAgIH0NCn0NCjGCAcowggHGAgEBMIGkMIGeMQowCAYDVQQFEwE1MQswCQYD -VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55dmFsZTESMBAGA1UE -ChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMGCSqGSIb3DQEJARYW -a2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2VsZiBTaWduZWQCAREw -BwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEggEAxyHPqb53KXaWJH1IE6IFp3zzm5vl -zlotcMxMepMRIxQPUDwJrP2ZJwXemQXVTpRa3Aer7hSkCRlyI++mcj/rD4h5Ygb0 -q9sscjfeZB11Y436E4ZhXCdTfrtmKyBlHMqyhTBz64zroN0P+DVH7OLZDX/gqN2U -KTX99HTN+LvUa8VqQYIzsjNv80CU6pog/YOCGPixjMKE9m9xYUr9huKZUxliHtX2 -AHoCfQPhI8nsnNHLzCx6u5xIM7A69ZIDPQ82hSHC58k+g0bq9uflRCixBSD7ulR7 -7ZRJM8IgOgFGpNeuyKcHJsCdPpZS8p1MmDCkwTOt5Kvf7Nopz+Cc325uOA== ------END CMS----- diff --git a/examples/pki/cms/auth_token_scoped.pkiz b/examples/pki/cms/auth_token_scoped.pkiz deleted file mode 100644 index a3177c16..00000000 --- a/examples/pki/cms/auth_token_scoped.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylVkmTmzgUvutXzN2VCotxm0MObMbQSG52ixtLG5DBdrttC_j1I3An6XRSk8wMVS6jJ_H0vfe97dMn9qiGaaG_NOiPi08AWpa1KbH9eEys6pYjxc21I5M9Dhp7ck1xjU4LlLVahme9hJpJNE3d56bmv5i-lYlAd421kjIhKY2yxNxzb1dYQE0uwnpTqw_WwbulQnS1yLFke6dcRHwSezu8ddm-UgNIFAprjkKf6zYrt4fBsUP6kSL-WDuaUifbiqZbu8l7a2FpVg91OHcCpXMCYx7pVgc2xOA2RBHj2nq1NPuUaONBm2bmiiRxdctMr8nve1wSS1V2cO_I2uiKY_sVJPEk4PJD1Iw3pvEdWmGOByRuKzR76E8K2JpvRlOYWU3Wrq7FSr6CUfh2YJ9sEcnbhhZmc8tqhsSU-Mzs5J1P2UfML4fkhIVIx1uvykz5MCoDsfhaM2jMr_IpO3jDKBxlOPYuaSxF4Z5OiNK1x-X68eYMRo_6OXWIcmX-mgM05IIj4s4ZMIdJ0kIhqbEAeTi4A4rDOQ4wTVrUbvSmxoTtBEVl1SMiu0mE5gYmqJrdJ3FxygTpKWvD-u4LiUu2o93dP6IAI4z_jkLlAW67E-YjP7jTdyzWHt3UyxsMLHGyU5t3G1KKaMC3ghg3RLwatXhIWpvgIRwA0iGfBFWFiNpiAc83sV0jgjskGPUu4kZ2GGUezYTmWqzRLjOba3qP0mzL2AGMUyk3wzv3rfxajFyP8FoWNPEH-YEpXP_IGviXtEmQ7PvRX1-ZACMV_4cJ8GvNKv9nzt33YBNYo3f_yGHv_ZXGfJUIYQ1GqCwxLok_3XRgWXjFbGOMf5b_7xTeFY31IjH5U9bc0YF_5t4d0V2hvxSQaQkJYRHQIoICyMEhajamIQBoJiQhpYRbS0DEEPE9M98cOp_g5m10SGP5GgjSG8UMkRn1DPkriCIbTjneVlyxVhZOv-wgyUcUjDpjsdFZEdNkAfrzX4Y6-F2s_44N8G_s_dlcWwYTPay-JWv1NgZOzsuv7P88FdHVpRhZKtYNfWOJZAJPi633LdzB13jPWlkYNTravWB-U3hXxGSrfRY3148-Ax-dBlmKoiBn5lhM9jMj4QdGwHtKfsfIL5RTULDansbod1nIQ12hLFd6tv4h7MGfxT3rAwfvVKz39YfQP4Nk2wyFKV8T5sD7h9GQbK23vji-v28o03o3KQiMSRnIWbVhDeUHBKxQsJYWfi0a43tvNdz71sfnQtSPXQu8daU-E7rmO2XN_u5MTFnY7nFQtSyQBkhcCRO7QgOrn2TVwiAXAA4KVkRh97EOTsgYzLe0_npzC3XUJqYxT0hVwcHiwCa2ehzkLBesLmHhiVoWoqxg_9xQ30w58MV7R4Lv9ky3d-yAvAtMTcmPtCzXplIaKrTMPfs9Q_dINQXrkeuuDGrw0H2lQHMngWlQOwoHw4HK3lT40NBUqLmc0RlEcdUSRaqSB1qE-KyVpIIFHTPPh6pigulwBe1AVJusQRyO0Rl6BtXppNgxaOV8ozowGqjBb_MRG49soHg4ZjOQlIveLWsjJRsVHe6KnFbuk8EIoWpNqJQOOqEQvSa1GqRxcWXDicYUGFSlePVI57pSHanuvp_YDFV1FTZ8GcrR8fnhBZ6Ka4w_z1waumEnBQICw9PlSQwpmuOXQEtDY1bOTjj9LPl8uh4cdbkwrm2OWkvkdNecc8q88Qq03ivo7FKXPokgTtSDB88PHJnrPsGz2usVbDw-n8O63D4f3dNgPKk7a_biR4EmIrWSU4srF7vhtnDD54cdmMmZX1mv-7amy94ZxKBOLw9pcsj4gX19SR_oSrDzM5JO9SyfyVJcbZ6e02A2S-OLTC4FkJf-jddP9bBYPl1m5Voqs3WnWhDXnVq-SMre4j9_3qsCryp28xwfnzDPZaQ4s5GkWyzkGNyiy9Z9sG_4Obsttd3jUhXFonIWc_9Y53m3ibLSDg2P1fIjuZ1Z3WnDTVPBLjy2p8H98gVME7OB9O_T89-mTsWe \ No newline at end of file diff --git a/examples/pki/cms/auth_token_scoped_expired.json b/examples/pki/cms/auth_token_scoped_expired.json deleted file mode 100644 index d9ea0e92..00000000 --- a/examples/pki/cms/auth_token_scoped_expired.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "access": { - "token": { - "expires": "2010-06-02T14:47:34Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "placeholder", - "tenant": { - "id": "tenant_id1", - "enabled": true, - "description": null, - "name": "tenant_name1" - } - }, - "serviceCatalog": [ - { - "endpoints_links": [], - "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" - } - ], - "type": "volume", - "name": "volume" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "image", - "name": "glance" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "compute", - "name": "nova" - }, - { - "endpoints_links": [], - "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" - } - ], - "type": "identity", - "name": "keystone" - } - ], - "user": { - "username": "user_name1", - "roles_links": [ - "role1", - "role2" - ], - "id": "user_id1", - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "name": "user_name1" - } - } -} diff --git a/examples/pki/cms/auth_token_scoped_expired.pem b/examples/pki/cms/auth_token_scoped_expired.pem deleted file mode 100644 index 43e09f33..00000000 --- a/examples/pki/cms/auth_token_scoped_expired.pem +++ /dev/null @@ -1,76 +0,0 @@ ------BEGIN CMS----- -MIINuQYJKoZIhvcNAQcCoIINqjCCDaYCAQExCTAHBgUrDgMCGjCCC8YGCSqGSIb3 -DQEHAaCCC7cEgguzew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIwMTAtMDYtMDJUMTQ6NDc6MzRa -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogInBsYWNlaG9sZGVyIiwNCiAgICAgICAg -ICAgICJ0ZW5hbnQiOiB7DQogICAgICAgICAgICAgICAgImlkIjogInRlbmFudF9p -ZDEiLA0KICAgICAgICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAg -ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgICAgICJu -YW1lIjogInRlbmFudF9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAgICAgfSwN -CiAgICAgICAgInNlcnZpY2VDYXRhbG9nIjogWw0KICAgICAgICAgICAgew0KICAg -ICAgICAgICAgICAgICJlbmRwb2ludHNfbGlua3MiOiBbXSwNCiAgICAgICAgICAg -ICAgICAiZW5kcG9pbnRzIjogWw0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAu -MTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInB1YmxpY1VSTCI6ICJodHRwOi8v -MTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYx -N2EiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0K -ICAgICAgICAgICAgICAgICJ0eXBlIjogInZvbHVtZSIsDQogICAgICAgICAgICAg -ICAgIm5hbWUiOiAidm9sdW1lIg0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAg -IHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQogICAg -ICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6Ly8x -MjcuMC4wLjE6OTI5Mi92MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVn -aW9uIjogInJlZ2lvbk9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJwdWJsaWNVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5 -MjkyL3YxIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAg -XSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpbWFnZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAiZ2xhbmNlIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQog -ICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAg -ICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6 -Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6 -ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicHVibGlj -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQz -NWU4YTYwZmNmODliYjY2MTdhIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAg -ICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjb21wdXRl -IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJub3ZhIg0KICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xp -bmtzIjogW10sDQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAg -ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWlu -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMToz -NTM1Ny92Mi4wIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJwdWJsaWNVUkwi -OiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAiDQogICAgICAgICAgICAgICAg -ICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJ0eXBl -IjogImlkZW50aXR5IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJrZXlzdG9u -ZSINCiAgICAgICAgICAgIH0NCiAgICAgICAgXSwNCiAgICAgICAgInVzZXIiOiB7 -DQogICAgICAgICAgICAidXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsDQogICAgICAg -ICAgICAicm9sZXNfbGlua3MiOiBbDQogICAgICAgICAgICAgICAgInJvbGUxIiwN -CiAgICAgICAgICAgICAgICAicm9sZTIiDQogICAgICAgICAgICBdLA0KICAgICAg -ICAgICAgImlkIjogInVzZXJfaWQxIiwNCiAgICAgICAgICAgICJyb2xlcyI6IFsN -CiAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICJuYW1lIjog -InJvbGUxIg0KICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgew0K -ICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJyb2xlMiINCiAgICAgICAgICAg -ICAgICB9DQogICAgICAgICAgICBdLA0KICAgICAgICAgICAgIm5hbWUiOiAidXNl -cl9uYW1lMSINCiAgICAgICAgfQ0KICAgIH0NCn0NCjGCAcowggHGAgEBMIGkMIGe -MQowCAYDVQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcT -CVN1bm55dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9u -ZTElMCMGCSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UE -AxMLU2VsZiBTaWduZWQCAREwBwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEggEAw7K9 -7FaxXE6QNbsWmTAo/mtppDB2hv2DCwxMnjaZuOlV3g7UGnF8mxHjWd2Pcj1r0oGb -0iACE9qmoZVHTPWU6WWBClAIF/bcs6Y+5S10bCu1uRVrzUCsLEbbJOLxBZG1qiEZ -opLn6pBIOY8ovxcoKKmI56JgsqVGclZM5yH9Z9E5hSZgMREJZFZcVHA3pTJeTjc2 -9Mpb3RS5Q/FXf2nP09YA4Mp9+J15gFH/YuhBQiyo+LqvHtg+DdWdxcM3keAaTuxw -Z8Cd26T+cTv1iS5qXcykd8OP7V0eIF7i39wshXGm6B9XpwFEYiLTZy7398O/yeGd -izImJNpCowBA0Pyr8w== ------END CMS----- diff --git a/examples/pki/cms/auth_token_scoped_expired.pkiz b/examples/pki/cms/auth_token_scoped_expired.pkiz deleted file mode 100644 index 5824b4ef..00000000 --- a/examples/pki/cms/auth_token_scoped_expired.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylVtuSmzgQfddX7PtUKiDsGfOQBy4yhrHEcLd4MzAGZLA99pjb16_Ak2QySW2yu66iDC3RnO5zulufPvGfigyT_KVhb3z4BLBpmnZOrcdjbBZNShQn1Y7c9jho_JdqioM6zVdWah6c9RxrBtM0dZ8amvdieGYiAd1BK2XLjSxHeU6F594qKCRVKuHSLtUH8-A2WxheTXbM-doplYgYR-6Obhy-rpQAM6XFpdBiT-jspdNj_9gR_dgS8ViuNaWMN0W73VhV2pv3pmb2WEft2lcgv_pQRwKwmSPZDAtRaV5MzTrF2rjRahNjyeKoaBLDrdLbmhBH8yI5ODdkdXilkXUBcTQZhPQQVuMXt9ENWmaMG-bCBlZ77E0O-LNYjaHwsKqkXl6zpXwFo_Ftwz7eEJbWVZsZVZOUHIkxFxOjk3dey1_ieTnEJwpDnW7cIjHkw-gMRNKl5NB4XuVTcnCH0TjaaOS-bqN5GOzbCdF25QqpfmzWA-pJP2vXTLnyfM0AGVK4lmi3HqhAWVxjGJcUYhEPzkCiYEZ92sY1qW29KinjK35WmOWIyKpiWDVggqpZfRxlpwTOn5I6KG-5mAvxZoy7-0cUYITx31GoIqB1d6Ji6Pk3-o7Zym3tctFg35SmOLVZZ7NcIgNtMoYawtyS1HSIa4vRIRgA0bEY-0VBmFpTSGd2ZJWE0Y5AVO5CYWSHU-a2Cayu2YrsEqO6bm8qTTacHcA5nadGcOO-li_ZyPUIr-aiiT7YD9zh6kfWwL-kbY7Zvh_z9ZUJMFLxf5gAv_asin-W3H0PbN8cs_tHCXufr20kFjEMSjBC5YXxGnvTlw68Cq-UL4z65_X_zuHN0dgvYkM8JdUNHfhn7p0R3RV7C0gME8aMK6AmjPhYwENY2QaCABsxi1k-p7UJCUMSvVXmW0JnE9y0Dg_bSL76cP5GMUdkhD1HfgFhaOGpxutCyFbK_bpfdJilIwpOHbq3dd7ENBlib_ZLqYPfaf13bIB_E-_P4VoymOjh_S1eqc0onFSUL_z_PDXR5Ws2spStqvaNJZZAsc027je5g696T2oZjh7X2q1hfnN4c8Rty30SVdePOQMfk4Z5iRI_5eGY3PYzI8EHRsB7Sn7HyC-ctyDjvX0bkd9VoYh1peW10vPnH2QP_kz3fA4c3FO22pcfpH8G8aYaMkO-xjyBtxfDId6Yb3NxvH8_UKbn3eTAR5MzkPJuwwfKDwh4o-AjLfjaNMb73qyE96NPTGHYj1MLvE2lPoFd9Z2yan9LJm25bPfUL2oupAEzZ06ZVZCB90-2rLGfQkD9jDdR3H3sgxMyDvOtrL9-ucY6qWMDzWJWFHgw-XSOzJ76Ka8Fs4u5PEnNJcob9s8D9S2Ug5i9TyT4Hs_09Y5vkHe-oSnpsc3zlaHkSMWmsefXM3aOraZQPXScJWqRiJ1LCzRnMhiotcJgQGus7A1FDJCmYs0RUIeY4qg5CVUl9bWQiEk9n2dcdDw8D6uKAabNBbZ8Sa2Sigg0ImfsolZvJ8dr1Bbrb1T7qMIa_nY-4scjCygujfgZaJ5KbpPUoZKMjg43R-ta7uMBBVg1J1RKh9cBDC9xqfrbKLvyw4nGHaBWbenysZ3pSnFsdef9iQ2pqqPwwxdShifbKSSRDulneAkzL_1s95acEXAHC8PNXUdeP_Qrz9qeXvW6znWfvOrq4irIun8XtKKPVnfijJEHMs9DT9RWUmE9KjynDFjbJfPxS7Mx0iWWFs9RWj46L3Z3V587XM1PWwNCXoTJ2UNDv1d9vvuz9tLXV_kxDWYYgqHYd8_N6XzoH2b-xWpw0y_gJtAsxErjRb5G4RbKz_YBO2VeLXPDpyxSbVs8N2ZTBVgCiztMAyErXrdbb7N_Me8fcjVnq9dBsKTF4alod0-SuyzE3LNe81ZdFU6TCv48WWXN-hB7O_B8DmemaSyebLh7CO6kaJFerYooCIa2zek7UjVGq6ck30Okq4_3s0OV2WpyLwkwwsqXL2A6MSOifz89_w1E1sSW \ No newline at end of file diff --git a/examples/pki/cms/auth_token_unscoped.json b/examples/pki/cms/auth_token_unscoped.json deleted file mode 100644 index 844cebd5..00000000 --- a/examples/pki/cms/auth_token_unscoped.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "access": { - "token": { - "expires": "2112-08-17T15:35:34Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "01e032c996ef4406b144335915a41e79" - }, - "serviceCatalog": {}, - "user": { - "username": "user_name1", - "roles_links": [], - "id": "c9c89e3be3ee453fbf00c7966f6d3fbd", - "roles": [ - { - "id": "359da42d31c04437a32812aeb79e9c0b", - "name": "role1" - }, - { - "id": "581af19726fa4af5bda745789ab2bf2b", - "name": "role2" - } - ], - "name": "user_name1" - } - } -} diff --git a/examples/pki/cms/auth_token_unscoped.pem b/examples/pki/cms/auth_token_unscoped.pem deleted file mode 100644 index 274ac386..00000000 --- a/examples/pki/cms/auth_token_unscoped.pem +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CMS----- -MIIE9gYJKoZIhvcNAQcCoIIE5zCCBOMCAQExCTAHBgUrDgMCGjCCAwMGCSqGSIb3 -DQEHAaCCAvQEggLwew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIxMTItMDgtMTdUMTU6MzU6MzRa -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogIjAxZTAzMmM5OTZlZjQ0MDZiMTQ0MzM1 -OTE1YTQxZTc5Ig0KICAgICAgICB9LA0KICAgICAgICAic2VydmljZUNhdGFsb2ci -OiB7fSwNCiAgICAgICAgInVzZXIiOiB7DQogICAgICAgICAgICAidXNlcm5hbWUi -OiAidXNlcl9uYW1lMSIsDQogICAgICAgICAgICAicm9sZXNfbGlua3MiOiBbXSwN -CiAgICAgICAgICAgICJpZCI6ICJjOWM4OWUzYmUzZWU0NTNmYmYwMGM3OTY2ZjZk -M2ZiZCIsDQogICAgICAgICAgICAicm9sZXMiOiBbDQogICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAiaWQiOiAiMzU5ZGE0MmQzMWMwNDQzN2Ez -MjgxMmFlYjc5ZTljMGIiLA0KICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJy -b2xlMSINCiAgICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAgIHsNCiAg -ICAgICAgICAgICAgICAgICAgImlkIjogIjU4MWFmMTk3MjZmYTRhZjViZGE3NDU3 -ODlhYjJiZjJiIiwNCiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAicm9sZTIi -DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgXSwNCiAgICAgICAgICAg -ICJuYW1lIjogInVzZXJfbmFtZTEiDQogICAgICAgIH0NCiAgICB9DQp9DQoxggHK -MIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5TdGFjazERMA8G -A1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25lQG9wZW5zdGFj -ay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIaMA0GCSqGSIb3 -DQEBAQUABIIBAMmrhRIUjSd+SLUAYn+18MDB8MXiaiF+FJQbu86IFW3OpL86ksvg -CTP44Rvu1F4vvoZAQ60/tOfFVNTnBgnMv0NEfl4huiFqYrXjCphnNFQ5OYnmU6LR -bFV+dvjZXWUn0wJDroUUEjbgyy/mqUnULzQgUzyK7Ho8T0dWahQc7EFMNVjoeKfa -K7DeRe9trNNHM8anKVaeKhpWIfzbxiwIwypukce6wVGfdhaP+58jeFnGwHUIsY8V -8rzWj9UN46ko61piMAZljcktbrpqw2fDJ1H9Xl23G83rnXY7uVLQWUe7fRcUFtQt -gQvKsGkN2hqlOgMT/FxFM3HC8kcl3wmzrNA= ------END CMS----- diff --git a/examples/pki/cms/auth_token_unscoped.pkiz b/examples/pki/cms/auth_token_unscoped.pkiz deleted file mode 100644 index 34f93f46..00000000 --- a/examples/pki/cms/auth_token_unscoped.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJxdVNmWqjoQfecr7nuvs5pBW30MIWKiCSKT5A1QZqQdEOTrb7DPHVmLIVWVqr03Vfn1S1w6MjH7A1JnWvySKMZGa4dk23KcPxMG7AS2wlaVEILZDAIbDdAFGz3zbkZGoTnZo5kJnavp4FiTDBttQCSMfImyzIzPL5KHKqsTjRZWoS_w5fCMVL_DZZsJ33eiMYUHhzQ82sIPComWoKeF3FNHHqy1_aJuOzCj7ZnSFjsICn7M--hI6uSFvzDEwo9eOxfMdi7SfAMpklVSRdxyUOA7huSbw3dgTwOvpyMpLbdSeRDKzABqWCLxpiNzq4EFSBYxmmQ5ZDVVSlT_dWrqknssP5nre6wmbwqp02f44o_8iH9Tmr5JFwZKPdGSfhvSuFk_uIvesJNmdedHlsZm3UU_WsTHKVFTV9Mm3NB5OGZz7rJCEo-au7ZCVV5woUc4JnNW8oY19sgbUuFiQkCesemP0-ZAuxdR8CMgHb25xE3BRQTTgPbMsEemopGW2UCbdR2WiahSl9TEb2RvlM6kEXnF6lBTQV_aQcHrL2ilN6PBuqFupVGBInQPOS_9QhTRmOFpllHnYUkEUlK8kTXzXIoD7w3nzdvFRerL09_4W6T_a5QelRUNsf6aGioJoSQ6rc8iu8_4bIAlwHrGfB14LnC9AY6A_KxDF9S-S-17D-3Q8G0bo54YtoscierABIqH9IEST_O7-FKrYSD4HXCPwDt4i_p6n5h-52kH0aX3Ablg_5P47koQPerzkcmxOheieD3u_z0Xlb7O-Y0f6_Fkrjru6c8pUfKTqIs1cpHowe5R9q5koP7h8mBo8Jp9c5GQC0boP4MEmJ5V17wqzFUv64L-WgLAEROnxy40lpf0Fg28fjkQr5bP1g0-Qt-trp_4RXab1bDZlQvFPkffLGmr62wLSLTYS9b2MhKrIzeowvOwgP35VOcfVbq7nLEefJzqb1nfpgf1dh0sdWM-QmW3WJwrvzBhh9bFl0R2kU3U3eqYwodf6ddV2OfzzAwWt0fqJI62dwS7fUn0wd2q22tM5LzxcyqjjMNZt46kpJtbY5PjW218jXuv1s3ncAZhvFAeymKFu2I8xOuxSZf-vH76-_IKeLy0WKvq7Hgbv6A0dJ-seV45vZufmqwrsZ68hlxvo2ZBFrkV55blvzbp_nOZmZes3LycHQkPVlzKz9N2OXxJS00ui6s_aPNNIDjeWsvY-vuP9mOuIel96iFm_HMC_gm2VKmF \ No newline at end of file diff --git a/examples/pki/cms/auth_v3_token_revoked.json b/examples/pki/cms/auth_v3_token_revoked.json deleted file mode 100644 index f2ddf29c..00000000 --- a/examples/pki/cms/auth_v3_token_revoked.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "token": { - "catalog": [ - { - "endpoints": [ - { - "id": "3b5e554bcf114f2483e8a1be7a0506d1", - "interface": "admin", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "54abd2dc463c4ba4a72915498f8ecad1", - "interface": "internal", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "70a7efa4b1b941968357cc43ae1419ee", - "interface": "public", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "5707c3fc0a294703a3c638e9cf6a6c3a", - "type": "volume", - "name": "volume" - }, - { - "endpoints": [ - { - "id": "92217a3b95394492859bc49fd474382f", - "interface": "admin", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "f20563bdf66f4efa8a1f11d99b672be1", - "interface": "internal", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "375f9ba459a447738fb60fe5fc26e9aa", - "interface": "public", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - } - ], - "id": "15c21aae6b274a8da52e0a068e908aac", - "type": "image", - "name": "glance" - }, - { - "endpoints": [ - { - "id": "edbd9f50f66746ae9ed11dc3b1ae35da", - "interface": "admin", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "9e03c46c80a34a159cb39f5cb0498b92", - "interface": "internal", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "1df0b44d92634d59bd0e0d60cf7ce432", - "interface": "public", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "2f404fdb89154c589efbc10726b029ec", - "type": "compute", - "name": "nova" - }, - { - "endpoints": [ - { - "id": "a4501e141a4b4e14bf282e7bffd81dc5", - "interface": "admin", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "3d17e3227bfc4483b58de5eaa584e360", - "interface": "internal", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "8cd4b957090f4ca5842a22e9a74099cd", - "interface": "public", - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne" - } - ], - "id": "c5d926d566424e4fba4f80c37916cde5", - "type": "identity", - "name": "keystone" - } - ], - "issued_at": "2002-01-18T21:14:07Z", - "expires_at": "2038-01-18T21:14:07Z", - "audit_ids": ["ZzzZ2ZZYqT8OzfUVvrjEITQ", "cCCCCCctTzO1-XUk5STybw"], - "project": { - "enabled": true, - "description": null, - "name": "tenant_name1", - "id": "tenant_id1", - "domain": { - "id": "domain_id1", - "name": "domain_name1" - } - }, - "user": { - "name": "revoked_username1", - "id": "revoked_user_id1", - "domain": { - "id": "domain_id1", - "name": "domain_name1" - } - }, - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "methods": [ - "password" - ] - } -} diff --git a/examples/pki/cms/auth_v3_token_revoked.pem b/examples/pki/cms/auth_v3_token_revoked.pem deleted file mode 100644 index ca2bf06b..00000000 --- a/examples/pki/cms/auth_v3_token_revoked.pem +++ /dev/null @@ -1,123 +0,0 @@ ------BEGIN CMS----- -MIIWqQYJKoZIhvcNAQcCoIIWmjCCFpYCAQExCTAHBgUrDgMCGjCCFLYGCSqGSIb3 -DQEHAaCCFKcEghSjew0KICAgICJ0b2tlbiI6IHsNCiAgICAgICAgImNhdGFsb2ci -OiBbDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6 -IFsNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAg -ICAgImlkIjogIjNiNWU1NTRiY2YxMTRmMjQ4M2U4YTFiZTdhMDUwNmQxIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAiYWRtaW4iLA0KICAg -ICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3 -NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAgICAg -ICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAg -ICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJpZCI6ICI1NGFiZDJkYzQ2M2M0YmE0YTcyOTE1NDk4 -ZjhlY2FkMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjog -ImludGVybmFsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1cmwiOiAiaHR0 -cDovLzEyNy4wLjAuMTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIg0KICAgICAgICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAg -ICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAiaWQiOiAiNzBhN2VmYTRi -MWI5NDE5NjgzNTdjYzQzYWUxNDE5ZWUiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgImludGVyZmFjZSI6ICJwdWJsaWMiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUz -NDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAg -InJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0NCiAg -ICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJpZCI6ICI1NzA3YzNm -YzBhMjk0NzAzYTNjNjM4ZTljZjZhNmMzYSIsDQogICAgICAgICAgICAgICAgInR5 -cGUiOiAidm9sdW1lIiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJ2b2x1bWUi -DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAg -ICJlbmRwb2ludHMiOiBbDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJpZCI6ICI5MjIxN2EzYjk1Mzk0NDkyODU5YmM0OWZk -NDc0MzgyZiIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjog -ImFkbWluIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDov -LzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJy -ZWdpb24iOiAicmVnaW9uT25lIg0KICAgICAgICAgICAgICAgICAgICB9LA0KICAg -ICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAiaWQi -OiAiZjIwNTYzYmRmNjZmNGVmYThhMWYxMWQ5OWI2NzJiZTEiLA0KICAgICAgICAg -ICAgICAgICAgICAgICAgImludGVyZmFjZSI6ICJpbnRlcm5hbCIsDQogICAgICAg -ICAgICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcuMC4wLjE6OTI5Mi92 -MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogInJlZ2lvbk9u -ZSINCiAgICAgICAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogIjM3NWY5YmE0NTlhNDQ3 -NzM4ZmI2MGZlNWZjMjZlOWFhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJp -bnRlcmZhY2UiOiAicHVibGljIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1 -cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIg0KICAgICAgICAgICAgICAg -ICAgICB9DQogICAgICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAiaWQi -OiAiMTVjMjFhYWU2YjI3NGE4ZGE1MmUwYTA2OGU5MDhhYWMiLA0KICAgICAgICAg -ICAgICAgICJ0eXBlIjogImltYWdlIiwNCiAgICAgICAgICAgICAgICAibmFtZSI6 -ICJnbGFuY2UiDQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAg -ICAgICAgICAgICJlbmRwb2ludHMiOiBbDQogICAgICAgICAgICAgICAgICAgIHsN -CiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICJlZGJkOWY1MGY2Njc0NmFl -OWVkMTFkYzNiMWFlMzVkYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJmYWNlIjogImFkbWluIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1cmwi -OiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc0L3YxLjEvNjRiNmYzZmJjYzUzNDM1ZThh -NjBmY2Y4OWJiNjYxN2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lv -biI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAg -ICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICI5 -ZTAzYzQ2YzgwYTM0YTE1OWNiMzlmNWNiMDQ5OGI5MiIsDQogICAgICAgICAgICAg -ICAgICAgICAgICAiaW50ZXJmYWNlIjogImludGVybmFsIiwNCiAgICAgICAgICAg -ICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc0L3YxLjEv -NjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAgICAgICAgICAg -ICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAg -ICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJpZCI6ICIxZGYwYjQ0ZDkyNjM0ZDU5YmQwZTBkNjBjZjdjZTQz -MiIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjogInB1Ymxp -YyIsDQogICAgICAgICAgICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcu -MC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdh -IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25l -Ig0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgXSwNCiAg -ICAgICAgICAgICAgICAiaWQiOiAiMmY0MDRmZGI4OTE1NGM1ODllZmJjMTA3MjZi -MDI5ZWMiLA0KICAgICAgICAgICAgICAgICJ0eXBlIjogImNvbXB1dGUiLA0KICAg -ICAgICAgICAgICAgICJuYW1lIjogIm5vdmEiDQogICAgICAgICAgICB9LA0KICAg -ICAgICAgICAgew0KICAgICAgICAgICAgICAgICJlbmRwb2ludHMiOiBbDQogICAg -ICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6 -ICJhNDUwMWUxNDFhNGI0ZTE0YmYyODJlN2JmZmQ4MWRjNSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJmYWNlIjogImFkbWluIiwNCiAgICAgICAgICAg -ICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTozNTM1Ny92MyIs -DQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIN -CiAgICAgICAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAgICAgICAgew0K -ICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogIjNkMTdlMzIyN2JmYzQ0ODNi -NThkZTVlYWE1ODRlMzYwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRl -cmZhY2UiOiAiaW50ZXJuYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVy -bCI6ICJodHRwOi8vMTI3LjAuMC4xOjM1MzU3L3YzIiwNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJyZWdpb24iOiAiUmVnaW9uT25lIg0KICAgICAgICAgICAgICAg -ICAgICB9LA0KICAgICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAg -ICAgICAgICAiaWQiOiAiOGNkNGI5NTcwOTBmNGNhNTg0MmEyMmU5YTc0MDk5Y2Qi -LA0KICAgICAgICAgICAgICAgICAgICAgICAgImludGVyZmFjZSI6ICJwdWJsaWMi -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAu -MC4xOjUwMDAvdjMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6 -ICJSZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAg -ICAgICBdLA0KICAgICAgICAgICAgICAgICJpZCI6ICJjNWQ5MjZkNTY2NDI0ZTRm -YmE0ZjgwYzM3OTE2Y2RlNSIsDQogICAgICAgICAgICAgICAgInR5cGUiOiAiaWRl -bnRpdHkiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogImtleXN0b25lIg0KICAg -ICAgICAgICAgfQ0KICAgICAgICBdLA0KICAgICAgICAiaXNzdWVkX2F0IjogIjIw -MDItMDEtMThUMjE6MTQ6MDdaIiwNCiAgICAgICAgImV4cGlyZXNfYXQiOiAiMjAz -OC0wMS0xOFQyMToxNDowN1oiLA0KICAgICAgICAicHJvamVjdCI6IHsNCiAgICAg -ICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAgICAgICJkZXNjcmlwdGlv -biI6IG51bGwsDQogICAgICAgICAgICAibmFtZSI6ICJ0ZW5hbnRfbmFtZTEiLA0K -ICAgICAgICAgICAgImlkIjogInRlbmFudF9pZDEiLA0KICAgICAgICAgICAgImRv -bWFpbiI6IHsNCiAgICAgICAgICAgICAgICAiaWQiOiAiZG9tYWluX2lkMSIsDQog -ICAgICAgICAgICAgICAgIm5hbWUiOiAiZG9tYWluX25hbWUxIg0KICAgICAgICAg -ICAgfQ0KICAgICAgICB9LA0KICAgICAgICAidXNlciI6IHsNCiAgICAgICAgICAg -ICJuYW1lIjogInJldm9rZWRfdXNlcm5hbWUxIiwNCiAgICAgICAgICAgICJpZCI6 -ICJyZXZva2VkX3VzZXJfaWQxIiwNCiAgICAgICAgICAgICJkb21haW4iOiB7DQog -ICAgICAgICAgICAgICAgImlkIjogImRvbWFpbl9pZDEiLA0KICAgICAgICAgICAg -ICAgICJuYW1lIjogImRvbWFpbl9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAg -ICAgfSwNCiAgICAgICAgInJvbGVzIjogWw0KICAgICAgICAgICAgew0KICAgICAg -ICAgICAgICAgICJpZCI6ICJmMDNmZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYz -MSIsDQogICAgICAgICAgICAgICAgIm5hbWUiOiAicm9sZTEiDQogICAgICAgICAg -ICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJpZCI6ICJmMDNm -ZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYzMSIsDQogICAgICAgICAgICAgICAg -Im5hbWUiOiAicm9sZTIiDQogICAgICAgICAgICB9DQogICAgICAgIF0sDQogICAg -ICAgICJtZXRob2RzIjogWw0KICAgICAgICAgICAgInBhc3N3b3JkIg0KICAgICAg -ICBdDQogICAgfQ0KfQ0KMYIByjCCAcYCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJ -BgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYD -VQQKEwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkB -FhZrZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIB -ETAHBgUrDgMCGjANBgkqhkiG9w0BAQEFAASCAQCy1xOK1+nQy8tL3fORdWkcp0Y5 -88cNgl4sXmJOE1TOOEauMyVWE188gtxHelVDCFWr8kICALvAnPX0UbIhoEaxscey -mvcUazUMP2WWSsBMgSXBfbl6amTZp5KMgpMmAuGjP1xok3yvOecEF6Szh8yE3Q5O -sNEKsMI5UiJTDU7WWSUp1Zs7E4UvFjAepZGhIQWOCxSvEnrl3Mfw1f7HWKDBlijR -4XnPqJPiTmYLjzyDmi31GOHWZM4nZxShHfidLblPV4AyA/gsCh27/cZxYW/Q+cyL -wfQogs4g7XfNgLdDHlbvv7NCS06RhydhLeiqNUcCp4hnZZC16KDPWzJ2Ql5y ------END CMS----- diff --git a/examples/pki/cms/auth_v3_token_revoked.pkiz b/examples/pki/cms/auth_v3_token_revoked.pkiz deleted file mode 100644 index cf27adff..00000000 --- a/examples/pki/cms/auth_v3_token_revoked.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJydWEt3ozgT3etXfPucPgPCpOPFLHgZ47FEwDws7QxODELYTvzA8OunsJ3uPDrT6a9z-uSE4FLdqntvlfLtG_wzHdej_7PIrP_hGyKeR4qGTf7ZcK845tQIcmsDzx5sy7LHgWUEzsmKjLG5ip_tFbFcYVnWNnCt2ZM78zIN2YEzNhbwcBM7q9WT-dBOlAzvZVZ6t954V2ZpoizcYZW38PNoV-buqMu15TGvg3I-a1bIW0-OmZt0ntisUm1XLtKg9Euj5MLoeB0WvssGLCIttWVJakcjLi9Jyk604wXFHkakc8qpZZRZPdrzGZxiTdoMnySZTYZTy_zu1bLqg3s1awjmFYuK2nedjohAZ2JSINqZNROjmkQ5ZtGypIKcvLKBD-hFlsbnbPJ6uOORVz4myg4OkA9jc5vXSTfHIwWdowuvId1qT2xnT6IiJsK5JVFwS-zl4hxsbUJWW8m0Ht6rrNahRJD6YTkabrl9gcLd4Z6l8tC_AAXdcusMq8qwWixS_RFq9CZDdC7Y9UNzfH548taXVCF4CQU-n7YcT1Q-6z8YyhzTdjE3lUU6PJwhZOtkl1lvcS_d5MBSXXkXVLB5WGTucP3SNcRTvcrd4TZbh69aqSt8PqlZSuWlA6Mq62Gd65G02QXWZjkOG4BwdySRp02FcSDW4OSLlUY7dlwK50hFWNKaAR_g5C7uqE1UHhUFFdA5zAZ-OikRFUAKfCkgtGbd47pUeCI5lsesGh6AH33614J6HROJpFGssJrWiESOwoWn-DaVQJATq2ONRYZKbF69ItMBatLyeiSuZOshyxxqhgBPH13N6-ZcvMU4VHJ7c5x2TkvbQXOGFm0GtMvxVGOnaccUJngNrCwZJipQOehoGgPfWcMhJR84zwT8KloWl6JdoZQXmvN0uc2wfp_V8Rk2ehEPjcKC1UHLXaJQAV_upKAuiEdUJxoFei8qntKiJ9wj8KEnWQ8D5TUvGL5yfpwAcaT4Vbs-6xb6ars-6xb6j3aB9h2Np6B71zsxUSkkqrAPwSkGiDbAgQ5CG6Xk0K7eXUBdeu5eqQwSXqaqvAjnqj4Ra6BQAR0QELz1o0BDBCIRDF9dIf2UQh8czDpavPeEHwF7TYDVvUgA_b8aeCkq-lnVClLyeg38Ca11RITXVxf4XamkqxRqQyA71llNFD_lFbVzBdyq5eWvaY1e8_qLtNaBXG1P6x4a-h1Vf9q819CIdawOawpaoG5Sg0MXqPd4kgJVUw_TblJCb99Q9XdMRZ9T9WtFRe_NgnZJDdQtaF_IKFBAxp0P06inNY8g7c7DPJIFu5IPvWbfIlULjt9iJ1EiiBgVLI0xE54GCh1w11FJHTdgPBj5bqwTu4AXyPsRt87c0aHHf60J2HzYZBjaOCb9gMn6OqH3hWJpuF-kg3Ow5XyyuzCyUJZj43ba3p2IyPsaQUudW9_ONUStISazwQer-qpTod_2Pw1LbsuaRib0n2nU5iBjULDtnMC9OgSTGR6Agbif9_8qMphUzQdo6DNsX4WG_tSFX6D5aQwLB1EQrckA3KWD_oL7SsEE0blI4Luh-FFR-v1i8R_URn_mwkFP7QOZ3WHwSTA2gADzTdCIgOaTfrRhWKIEFyvwAxCXcDR2ofoVyuC68lx0EWFdoremOaq4MEtqhxWkDj4ZVgAL2mhK4gYQHDwTUwm233prdXmeTMuxbK7UFbDGNMt5-M6JJzW1DQVWvtK3-ykVQsYrHey-ZJ3TwJbmgUiM1k8T8d6Js3qI2Y8JnRz42Dz2nLgsnfuzvaF3Y7vgrrqFFn7F2jqonYpoC4RpPxYqflWoN5BqR6GRceqnEklhMjERShKFvecNSL9c1Lzm9qrnufoyRD7Oi4szg_R36Gsc6Ckca-DE3Xu29p44-4yuBAcwM2LYi70-MxiowYBgT_XdUNI0KVgUDxB1YZwL44-c-HWm6G2qIBDbALqSj04sfz3eAII3YDhQ-tFGO0MnLsgXO6pvBy2LvLZ3YNBA44PQuPVxDYAdKZSQ9nY5rt7gZ11ypjO3Y9BE0AJUYGO_NzFQLwH7B1bWtEI8it-78TOfy27p9qm-nJh0fO5dV_3wmKWj7cuV6MeW9nNjl7BgnjGChanXvl8_JIfnZ5cF9HIoernm8Dk_LnBSzbX-tMn1xddT68M757sDuq7xxTKFOvQXj-vQ8OT29kFu2lRueZ4Eg0jb1knCcV5vR7MkDC_0pjaC6WcHmCrJeHtPZipL0p0aq6HO1vn5Wge0hWteIvloWCwv87OFVrdT0MM0cgYosT3ov6P4wtBS2EIeI9cy8k2zWo1dY-WYxHMr-P9Agk1jGcxOgmDkNDAbg11jBcxG8MB1mkkSd86UGJVrqLFjmcQKFOfkCCMwVzQxjTyyEqpmta4vQUCgxBkxjfO7yCrIJNJMmUmqgNqeSeg0dnM-aeo0xfRHSyNHEov8uPLCjXdihCxFUFU916BNdWJkfaD1JdC0Hra8c2JieueTjBOZxjjZ8dKMFunywFO4V8NhyGzY6J9mYBvFprGD15dwxzQDA-7TjtGOxMIPR9FjE37XlON2OLSOB7sjD972Dj3vk-d2KBcPs-i21Uf3T1YNbT7l2DUf13g_cx-GOztaP5Uj9n3HlcmoCOybMtQmpSKD5BQhO1wbnuf8VQxq81BFdydp7pVVfCrNm25YBtSST48zfdt8V7ARb2Ot3DaMTjl_rr2tk_ylofomW_jOatpsRxv_xr9ZVVYs75RsIBUdVHqzte-8gzmYPVZW87zOHruTtDb5Kdb8h0X2qHkomd3WT8Pd6GCnj3KCT-U8NZXn440q0yM7TXLn4K6G08aLk0qtd_e3M3pj4XEi56UbYWMNV1823R3Nm6ySHdnj1nkw_MhV8NPqefKPqdLh-AFnnXW_N-82BSmq2VgeqvvWHAyCv_9G5z-CONT--QeRfwEmaLr4 \ No newline at end of file diff --git a/examples/pki/cms/auth_v3_token_scoped.json b/examples/pki/cms/auth_v3_token_scoped.json deleted file mode 100644 index 0fd000a0..00000000 --- a/examples/pki/cms/auth_v3_token_scoped.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "token": { - "methods": [ - "password" - ], - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "issued_at": "2002-01-18T21:14:07Z", - "expires_at": "2038-01-18T21:14:07Z", - "audit_ids": ["VcxU2JYqT8OzfUVvrjEITQ", "qNUTIJntTzO1-XUk5STybw"], - "project": { - "id": "tenant_id1", - "domain": { - "id": "domain_id1", - "name": "domain_name1" - }, - "enabled": true, - "description": null, - "name": "tenant_name1" - }, - "catalog": [ - { - "endpoints": [ - { - "id": "3b5e554bcf114f2483e8a1be7a0506d1", - "interface": "admin", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "54abd2dc463c4ba4a72915498f8ecad1", - "interface": "internal", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "70a7efa4b1b941968357cc43ae1419ee", - "interface": "public", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "5707c3fc0a294703a3c638e9cf6a6c3a", - "type": "volume", - "name": "volume" - }, - { - "endpoints": [ - { - "id": "92217a3b95394492859bc49fd474382f", - "interface": "admin", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "f20563bdf66f4efa8a1f11d99b672be1", - "interface": "internal", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "375f9ba459a447738fb60fe5fc26e9aa", - "interface": "public", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - } - ], - "id": "15c21aae6b274a8da52e0a068e908aac", - "type": "image", - "name": "glance" - }, - { - "endpoints": [ - { - "id": "edbd9f50f66746ae9ed11dc3b1ae35da", - "interface": "admin", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "9e03c46c80a34a159cb39f5cb0498b92", - "interface": "internal", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "1df0b44d92634d59bd0e0d60cf7ce432", - "interface": "public", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "2f404fdb89154c589efbc10726b029ec", - "type": "compute", - "name": "nova" - }, - { - "endpoints": [ - { - "id": "a4501e141a4b4e14bf282e7bffd81dc5", - "interface": "admin", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "3d17e3227bfc4483b58de5eaa584e360", - "interface": "internal", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "8cd4b957090f4ca5842a22e9a74099cd", - "interface": "public", - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne" - } - ], - "id": "c5d926d566424e4fba4f80c37916cde5", - "type": "identity", - "name": "keystone" - } - ], - "user": { - "domain": { - "id": "domain_id1", - "name": "domain_name1" - }, - "name": "user_name1", - "id": "user_id1" - } - } -} diff --git a/examples/pki/cms/auth_v3_token_scoped.pem b/examples/pki/cms/auth_v3_token_scoped.pem deleted file mode 100644 index 50641147..00000000 --- a/examples/pki/cms/auth_v3_token_scoped.pem +++ /dev/null @@ -1,123 +0,0 @@ ------BEGIN CMS----- -MIIWmgYJKoZIhvcNAQcCoIIWizCCFocCAQExCTAHBgUrDgMCGjCCFKcGCSqGSIb3 -DQEHAaCCFJgEghSUew0KICAgICJ0b2tlbiI6IHsNCiAgICAgICAgIm1ldGhvZHMi -OiBbDQogICAgICAgICAgICAicGFzc3dvcmQiDQogICAgICAgIF0sDQogICAgICAg -ICJyb2xlcyI6IFsNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiaWQi -OiAiZjAzZmRhOGY4YTMyNDliMmE3MGZiMWYxNzZhN2I2MzEiLA0KICAgICAgICAg -ICAgICAgICJuYW1lIjogInJvbGUxIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiaWQiOiAiZjAzZmRhOGY4YTMyNDliMmE3 -MGZiMWYxNzZhN2I2MzEiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogInJvbGUy -Ig0KICAgICAgICAgICAgfQ0KICAgICAgICBdLA0KICAgICAgICAiaXNzdWVkX2F0 -IjogIjIwMDItMDEtMThUMjE6MTQ6MDdaIiwNCiAgICAgICAgImV4cGlyZXNfYXQi -OiAiMjAzOC0wMS0xOFQyMToxNDowN1oiLA0KICAgICAgICAicHJvamVjdCI6IHsN -CiAgICAgICAgICAgICJpZCI6ICJ0ZW5hbnRfaWQxIiwNCiAgICAgICAgICAgICJk -b21haW4iOiB7DQogICAgICAgICAgICAgICAgImlkIjogImRvbWFpbl9pZDEiLA0K -ICAgICAgICAgICAgICAgICJuYW1lIjogImRvbWFpbl9uYW1lMSINCiAgICAgICAg -ICAgIH0sDQogICAgICAgICAgICAiZW5hYmxlZCI6IHRydWUsDQogICAgICAgICAg -ICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgIm5hbWUiOiAidGVu -YW50X25hbWUxIg0KICAgICAgICB9LA0KICAgICAgICAiY2F0YWxvZyI6IFsNCiAg -ICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzIjogWw0KICAg -ICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAiaWQi -OiAiM2I1ZTU1NGJjZjExNGYyNDgzZThhMWJlN2EwNTA2ZDEiLA0KICAgICAgICAg -ICAgICAgICAgICAgICAgImludGVyZmFjZSI6ICJhZG1pbiIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3Ni92MS82 -NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAg -ICAgICAgICAgICAicmVnaW9uIjogInJlZ2lvbk9uZSINCiAgICAgICAgICAgICAg -ICAgICAgfSwNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAg -ICAgICAgICAgImlkIjogIjU0YWJkMmRjNDYzYzRiYTRhNzI5MTU0OThmOGVjYWQx -IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAiaW50ZXJu -YWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUi -DQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIHsN -CiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICI3MGE3ZWZhNGIxYjk0MTk2 -ODM1N2NjNDNhZTE0MTllZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJmYWNlIjogInB1YmxpYyIsDQogICAgICAgICAgICAgICAgICAgICAgICAidXJs -IjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3Ni92MS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9u -IjogInJlZ2lvbk9uZSINCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAg -ICAgICAgIF0sDQogICAgICAgICAgICAgICAgImlkIjogIjU3MDdjM2ZjMGEyOTQ3 -MDNhM2M2MzhlOWNmNmE2YzNhIiwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJ2 -b2x1bWUiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogInZvbHVtZSINCiAgICAg -ICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgImVuZHBv -aW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAg -ICAgICAgICAgImlkIjogIjkyMjE3YTNiOTUzOTQ0OTI4NTliYzQ5ZmQ0NzQzODJm -IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAiYWRtaW4i -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAu -MC4xOjkyOTIvdjEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6 -ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAg -ICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICJmMjA1 -NjNiZGY2NmY0ZWZhOGExZjExZDk5YjY3MmJlMSIsDQogICAgICAgICAgICAgICAg -ICAgICAgICAiaW50ZXJmYWNlIjogImludGVybmFsIiwNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIg0KICAg -ICAgICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiaWQiOiAiMzc1ZjliYTQ1OWE0NDc3MzhmYjYw -ZmU1ZmMyNmU5YWEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImludGVyZmFj -ZSI6ICJwdWJsaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJo -dHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0N -CiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJpZCI6ICIxNWMy -MWFhZTZiMjc0YThkYTUyZTBhMDY4ZTkwOGFhYyIsDQogICAgICAgICAgICAgICAg -InR5cGUiOiAiaW1hZ2UiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogImdsYW5j -ZSINCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAg -ICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAg -ICAgICAgICAgICAgICAgICAgImlkIjogImVkYmQ5ZjUwZjY2NzQ2YWU5ZWQxMWRj -M2IxYWUzNWRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2Ui -OiAiYWRtaW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRw -Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5 -YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogInJl -Z2lvbk9uZSINCiAgICAgICAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAg -ICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogIjllMDNjNDZj -ODBhMzRhMTU5Y2IzOWY1Y2IwNDk4YjkyIiwNCiAgICAgICAgICAgICAgICAgICAg -ICAgICJpbnRlcmZhY2UiOiAiaW50ZXJuYWwiLA0KICAgICAgICAgICAgICAgICAg -ICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNm -YmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAg -ICAgICAicmVnaW9uIjogInJlZ2lvbk9uZSINCiAgICAgICAgICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAg -ICAgImlkIjogIjFkZjBiNDRkOTI2MzRkNTliZDBlMGQ2MGNmN2NlNDMyIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAicHVibGljIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo4 -Nzc0L3YxLjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAg -ICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAg -ICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAg -ICAgICAgICJpZCI6ICIyZjQwNGZkYjg5MTU0YzU4OWVmYmMxMDcyNmIwMjllYyIs -DQogICAgICAgICAgICAgICAgInR5cGUiOiAiY29tcHV0ZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAibm92YSINCiAgICAgICAgICAgIH0sDQogICAgICAgICAg -ICB7DQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAg -ICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogImE0NTAx -ZTE0MWE0YjRlMTRiZjI4MmU3YmZmZDgxZGM1IiwNCiAgICAgICAgICAgICAgICAg -ICAgICAgICJpbnRlcmZhY2UiOiAiYWRtaW4iLA0KICAgICAgICAgICAgICAgICAg -ICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjM1MzU3L3YzIiwNCiAgICAg -ICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAiUmVnaW9uT25lIg0KICAgICAg -ICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAgICAgICB7DQogICAgICAg -ICAgICAgICAgICAgICAgICAiaWQiOiAiM2QxN2UzMjI3YmZjNDQ4M2I1OGRlNWVh -YTU4NGUzNjAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImludGVyZmFjZSI6 -ICJpbnRlcm5hbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAidXJsIjogImh0 -dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjMiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgInJlZ2lvbiI6ICJSZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0s -DQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAg -ICJpZCI6ICI4Y2Q0Yjk1NzA5MGY0Y2E1ODQyYTIyZTlhNzQwOTljZCIsDQogICAg -ICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjogInB1YmxpYyIsDQogICAg -ICAgICAgICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcuMC4wLjE6NTAw -MC92MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lv -bk9uZSINCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIF0s -DQogICAgICAgICAgICAgICAgImlkIjogImM1ZDkyNmQ1NjY0MjRlNGZiYTRmODBj -Mzc5MTZjZGU1IiwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpZGVudGl0eSIs -DQogICAgICAgICAgICAgICAgIm5hbWUiOiAia2V5c3RvbmUiDQogICAgICAgICAg -ICB9DQogICAgICAgIF0sDQogICAgICAgICJ1c2VyIjogew0KICAgICAgICAgICAg -ImRvbWFpbiI6IHsNCiAgICAgICAgICAgICAgICAiaWQiOiAiZG9tYWluX2lkMSIs -DQogICAgICAgICAgICAgICAgIm5hbWUiOiAiZG9tYWluX25hbWUxIg0KICAgICAg -ICAgICAgfSwNCiAgICAgICAgICAgICJuYW1lIjogInVzZXJfbmFtZTEiLA0KICAg -ICAgICAgICAgImlkIjogInVzZXJfaWQxIg0KICAgICAgICB9DQogICAgfQ0KfQ0K -MYIByjCCAcYCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYD -VQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sx -ETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVu -c3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkq -hkiG9w0BAQEFAASCAQCPCzpknZOfDONpHDWGrYTeyirjGGjrJem2EF2qsJ4K1x/V -guNLX1AfRnRUC95wSpGS5VCQ+OSfSFmLjJQOnMqLZ1L2MkVfn0CIkqig19sgRZ+O -hpi+0TpJ6XlCWRERJEICCOAHZ/M2iiiVFbFkIGtaJLw3HcXFreV+nEBuQSeIGH/H -FjnmocYu9vy612YT47HcyQKNMaku3QBLzFTSTiGkS4ft9yT2pNMbHZsMmysaRKWl -SfuA/DZHT6zi5D4lkxDBCexf3JAw4kOQSf/dirfDUKmIy4VPeAOuO1u86hN/coIS -JvgAJGOVUxtZCQ9256dUvKa1pLpQAgW/Ok3oPulS ------END CMS----- diff --git a/examples/pki/cms/auth_v3_token_scoped.pkiz b/examples/pki/cms/auth_v3_token_scoped.pkiz deleted file mode 100644 index 3365dfe5..00000000 --- a/examples/pki/cms/auth_v3_token_scoped.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylWEl34rwS3etXvH2fPu0BElh6wthBcmw8IO2wnWDLNiRh8PDrXwlId4bu70u_lyxycKBUt-reWyW-f4cf3bId8h8DL8WL7wg7Ds5b6t7tmFOcMqL5mbGDZ2vTMEzbNzTf6oxQm-ub6MXcYMPmhmHsfNtYPttLJ1WR6VtzbQ0Pt5G12Tx1D70rpcqhTkvnxpnvyzSJpbU9rbIeXs_2ZWbPhkzNT1njl6tlu0HO1j2ldjw4fLdJ1H25TvzSK7WScW1gTVB4Nh3REPfErEvcWCq2WYkT2pGBFURxFIQHq1wYWpk2swNbwimG26dKV-OlO10Y-q3T1JUI7jS0xQqraFg0nm0NmPtjyt0CkUFvKJ81OMwUGuYl4bhzyhY-MC7SJDpnkzXTPQud8jGW9nBA_TDXn7ImHlbKTELn6Nxp8bA5YNM64LCIMLducOjfYDNfn4NtdcjqqaaqgCeyCk5pMnsSdUKiUD9x29MDTerjSqkrvHTEaUeayPUFwvVD9fT87AJRKxFLxgVtupoZoupBnyeR-ODT-bXhSuL_6TZ4hEM-Qcvt-IhoMpZWyvnh9Q1BnSmkX690aZ1Mj-L0dBvv0_kZP6eroEjt6fa1ayKDKrOnT3DKm1aOJbZyG5qQa_qzKgVol3rEfXrJbpfPgxZ55eSEQ0ddcO2IjVHn8Y1KBnrKuXUiPChJQ4EPcPIQDcTEMguLgnDonEJHXuKWiHAghXLhArRm-5o2EKxmSn1Kq-mRXQp6rYszUB7XJIwk2pAG4dCSGHckzyQ1EKSjTaTSUJOxyao3ZDpCwXrWzPiVbAJynUFBEeAR0eWsac-VXc8DKTN3p8Vg9aQftWdo4W5EhkxZqLRbDFSinDXAypIqWAYq-wNJIuA7bRmk5AHnKYd_hXlxKdoVSnmhOUvyp1QZ36dNdIaNXklEwgD44PfMxhLh8Gu7BbFBPLzqSOiPhahYQgpmWuUjqBBUe4aBsoYVVLlyfh6XqV3z37XrT91CX23Xn7qF_qFdoH1LZQno3nY6yisJh5XiQXCiAEQT4EAHoY11zaBdwl2cbTDO7CvPQcK5ENKZ3ldP4JEKCuXQAQ7Bey_0VYQhElbgdyhqLyHQB0uhAyk-Cec14BY0AQp-lQD6XzXwWlT0q6oVpOQIDfwNrccIc0dUF_hdyXioJGJCIDMa0wZLXsIqYmYSuFXPyt_TGr3l9RdpPQZy9YLWAhr6N6r-snmnJSEdaBM0BLRA7LgBhy6Q8HicAFUTRyGDW0Jv31H135iK_kzVrxUVfTQLMsQNULcgopChL4GMBw-mkaA1CyHtwVFYWBf0Sj70ln3rRC6Y8h47DmOO-aygSaRQ7qig0BGzLRk3UQvGoyDPjsbYLOAN-OOI26b27CjwX2tSp03Qpgq0cY7FgElFndDHQtEkOKyT0TlYvnL3F0YWUj7Xbhb9pMM8EzWCllo3npmpiBhTBS9Hn6zqq06F_rX_SVAys25IqEP_qUpMBjIGBZtWB-41IJjM8AAMxP5z_68ig5nYfoKG_oTtq9DQ37rwKzQviWDhwBIiDR6BuwzQX3DfmlOOx4zH8FeTvLAoPbFY_AO10d-5sC-ofcTLiQI-CcYGEGC-cRJi0HwsRpsCSxRnfAN-AOLilkovVL9CGV1XnosuQmVco_emOasY10tiBhWkDj4ZVAAL2qjX2PYhOHimQmqw_d7Zyvl5MuXzur1Sl6eK3Oar4IMTuw0xNQlWvtIzxZQKIOPNGOy-pIPVwpbmgEi03kti_tGJ02aq0J8TOj6yuX4SnLgsnYezvaEPY7tgtiy2r69Y2wC1kxHpgTD950JFbwr1DlJjSSTUOjGVcAKTifKgxmEgPG-ExXLRsIaZG8Fz-XWIfJ4XF2cG6e_R1zggKByp4MTDR7YKT1z-ia5Y8WFmRLAXOyIzGKj-CCuO7NlBTZK4oGE0QsSGcc61v3Lit5mi96mCQEwN6Io_O3H9-_EGEJwRVXxJjDYyaGNsg3wVS_ZMv6eh0wsHBg20HgiNGZ_XANiRghrSfsrn1Tv8dIjPdGZmBJrwe4AKbBR7EwX1YrB_YGVDKsTC6KMbv7BVPeS2SPX1xHhgK-fTqi9ajP6fVV8ciq6nypkS9--39ivzzqe7l3V_e97YizwByLPpE4P5gMSAcGrGH2ZRv6zrLjaL-4eGxfGW9esqduPZdTZG4zi26juoV_RQTbpFXMTrIQ5RPK_LvHfP2l6vyJAncSXuQj-vQqbz-6vQVp5i6uioh4ukllFxwWw3a7_dsFFncM3RNyTWtSjUwqgzBs29vIZpWMch9vet4VMz9n0HWa1r-qG1xLpma3Jk6R12IzU-pttaoQlc_wKntbTzm--str7P4JoTqbAWK_vOCrV7dIm8Dw3rUD-sCNxax1DlqHXeXYcrHcbPr_ZG-kkEyiAQgkjHVHW3OPBba3M-ybTaQ8iSrnFm5IlBQAaIrHf3Z43om-q5qEobTVtJB_wzTVtCHfQyJe6ErBKVzTaj52ktJzfLb5v18ZmC1e32cXCI5qRZzslkMg823voBTYYq2m8GfXVblmo0dM3LjN3xqVkYCzr6sV1KyTqii1l6WDem8cKauebfL3da5hH1YX0kB3S3s8JH95Yrw_PIcQ-yjZenh4leSlL5GLTsx2EXLshhkdaPVjtbG_2tGo-Ml930B6tGP4y9h0aBP1TLYtZNb8udfW9NW0t2T1M6dLvxMdzcDMroZlOOlIexdFw6M4Ybgp-rKB-k7Y2fHb4hecCPk-Tbg_zUV3f7LNaH2_HtbLr99qwVnTxedF1u3DkvvgwjZpJr_SLQ_Uh6Zg-LZnFaqgnaNo8_3Nq_XZh-86yufGsepL68H-fDj6bFE6dcNhN0_rLDIuavLz7-Cz0ItdI= \ No newline at end of file diff --git a/examples/pki/cms/revocation_list.der b/examples/pki/cms/revocation_list.der deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/pki/cms/revocation_list.json b/examples/pki/cms/revocation_list.json deleted file mode 100644 index 766c69c9..00000000 --- a/examples/pki/cms/revocation_list.json +++ /dev/null @@ -1 +0,0 @@ -{"revoked": [{"expires": "2112-08-14T17:58:48Z", "id": "db98ed2af6c6707bec6dc6c6892789a0"}, {"expires": "2112-08-14T17:58:48Z", "id": "15ce05fd491b79791068ed80a9c7f5e7"}, {"expires": "2112-08-14T17:58:48Z", "id": "db98ed2af6c6707bec6dc6c6892789a0"}, {"expires": "2112-08-14T17:58:48Z", "id": "15ce05fd491b79791068ed80a9c7f5e7"}]} \ No newline at end of file diff --git a/examples/pki/cms/revocation_list.pem b/examples/pki/cms/revocation_list.pem deleted file mode 100644 index 0e81998b..00000000 --- a/examples/pki/cms/revocation_list.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CMS----- -MIIDTwYJKoZIhvcNAQcCoIIDQDCCAzwCAQExCTAHBgUrDgMCGjCCAVwGCSqGSIb3 -DQEHAaCCAU0EggFJeyJyZXZva2VkIjogW3siZXhwaXJlcyI6ICIyMTEyLTA4LTE0 -VDE3OjU4OjQ4WiIsICJpZCI6ICJkYjk4ZWQyYWY2YzY3MDdiZWM2ZGM2YzY4OTI3 -ODlhMCJ9LCB7ImV4cGlyZXMiOiAiMjExMi0wOC0xNFQxNzo1ODo0OFoiLCAiaWQi -OiAiMTVjZTA1ZmQ0OTFiNzk3OTEwNjhlZDgwYTljN2Y1ZTcifSwgeyJleHBpcmVz -IjogIjIxMTItMDgtMTRUMTc6NTg6NDhaIiwgImlkIjogImRiOThlZDJhZjZjNjcw -N2JlYzZkYzZjNjg5Mjc4OWEwIn0sIHsiZXhwaXJlcyI6ICIyMTEyLTA4LTE0VDE3 -OjU4OjQ4WiIsICJpZCI6ICIxNWNlMDVmZDQ5MWI3OTc5MTA2OGVkODBhOWM3ZjVl -NyJ9XX0xggHKMIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMx -CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5T -dGFjazERMA8GA1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25l -QG9wZW5zdGFjay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIa -MA0GCSqGSIb3DQEBAQUABIIBAGn4kryxJudTZYMf32gKnoNHeAXRb97CoCXiTgs2 -gu/blX/fwMdrL8GLg2puYR07XBgjo56vMsD94ZIRyhcS1lFti9veQHt7Xp8kbR8l -nbx9fsOhMxUHLRnxioieA9T1ykP8ZvYV3hYCeXkIYhPgD4lAAAmNq99ZxBRS3csE -DP+Xz1+UYvT6Qm/NWRuj7WIjofneIB7gT6L5irsU0qtMCQeqI3dsP9GSsy4HJvBR -BBIzQ7fEMRCGTADbk4ml+6Dx+Jm5SO80NvinzxCjO3DbkcEG1pQ3RGVEn3gyzg2a -ssaRU4ycbYACA99K5UzCtSj8glGXFa1cnx42nSn2LbfJP1M= ------END CMS----- diff --git a/examples/pki/cms/revocation_list.pkiz b/examples/pki/cms/revocation_list.pkiz deleted file mode 100644 index 566d3318..00000000 --- a/examples/pki/cms/revocation_list.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJx9VElzszgUvPMr5p5KBbPY5vAdtGAsYokAYr0ZbIvdSXDM8usHO1Uzl6lRlQ6v1dVPr6vrvb4uB5oWYX8h6j-KV4kSgvmQ2O_XlBT3nAE3R9cFczFCYB4QcM0RcbCHIvjGgiKrWvBwsJD_ZfkkUyXsmntwXMBANoXY2efJntI4vR-VsCbVVURqX6ZxMRxju8knsiaITJSb04ED7cBNWQqxqTpVoDmVq0Ul6QmyP1P0INp1UtVaGrlTEiVKMicqxacyjaiSWvRRaw4nquTgpqDINg4IbkgbarnVLD-gpVOCklbmSEt5cJA8sp07svm6cvBVdnbX8oBAeYzcUnoSeVilHKzS1pUdvivZXKsONwdWFU2KxZDwpmJKskp5Xl78QSxjNuc9_MzbcJYec5KKjJSTG8XiRrkXUJ6vGRdrhosjKQdB2ubpB2m90uEPUbtIq7RiVT5ITLGbZE7r5S6A0GmVa05kDqSTe7L_fwMf_kn_bSAZWcQaisM2xa5OI7KMlOuUA8WxwtrBsHAiqqZV2Ehsso04lkch9u9LJuAoCAQcwU-MYFeZ7xQIC6wCE3oUMm4eKKh_68X6MKSjhGZgQ8FCCAQHNYPUI4MJEhy67t4cGn6K9J9znBaZFYxmBdxf7pWjwBjSSOfSydpVx9n0KNg-ldFIia-Eeq5696wNRpuDCor6q6hLyxhkiFwz2rW35hwzOVP0RnKtp9L8FJr0e97m4w4D_7cT5WjFmsxKRKA0XdaGNRCPZrkF_d4BAzlKFMj_5HqJNQRuAODiBbA6rf6eRvvnxNOEXlRFvHdXtj-D2MuMDbqiuOSiVyTx85Y18dtloKfvw9Y6COXzJ_HkTQxFddXXd9pjQ0uJNxW5v2p2t9K4n939bRN_buvM2zZSl43GpXcKOgb7g9eN5bU8A4Ovpvpjm96TUC0SdI5rkhQfAmsNAKBlX4aRjtDz1bw3JfzxEs-rlyC587XbvrHI-6k20ZK7S3cmcCP4-qCX330gf90ocs9fRD31H4bl95O2t-_QkyAks7u5mNRDFgc4q7W2eVnj8cVudd_ZyuxedvOIKkdd3nLTWn26qmeFZqeKaRbKUer7oxdoU54lAAHDeNeDGd38aisaK94dV3k3akrnd8ohu9gfK_pHeu4hk-F_d9Lf2fB_ww== \ No newline at end of file diff --git a/examples/pki/gen_cmsz.py b/examples/pki/gen_cmsz.py deleted file mode 100644 index 6840c08e..00000000 --- a/examples/pki/gen_cmsz.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/python - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json -import os - -from keystoneclient.common import cms -from keystoneclient import utils - -CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) - - -def make_filename(*args): - return os.path.join(CURRENT_DIR, *args) - - -def generate_revocation_list(): - REVOKED_TOKENS = ['auth_token_revoked', 'auth_v3_token_revoked'] - revoked_list = [] - for token in REVOKED_TOKENS: - with open(make_filename('cms', '%s.pkiz' % name), 'r') as f: - token_data = f.read() - id = utils.hash_signed_token(token_data.encode('utf-8')) - revoked_list.append({ - 'id': id, - "expires": "2112-08-14T17:58:48Z" - }) - with open(make_filename('cms', '%s.pem' % name), 'r') as f: - pem_data = f.read() - token_data = cms.cms_to_token(pem_data).encode('utf-8') - id = utils.hash_signed_token(token_data) - revoked_list.append({ - 'id': id, - "expires": "2112-08-14T17:58:48Z" - }) - revoked_json = json.dumps({"revoked": revoked_list}) - with open(make_filename('cms', 'revocation_list.json'), 'w') as f: - f.write(revoked_json) - encoded = cms.pkiz_sign(revoked_json, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME) - with open(make_filename('cms', 'revocation_list.pkiz'), 'w') as f: - f.write(encoded) - - encoded = cms.cms_sign_data(revoked_json, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME) - with open(make_filename('cms', 'revocation_list.pem'), 'w') as f: - f.write(encoded) - - -CA_CERT_FILE_NAME = make_filename('certs', 'cacert.pem') -SIGNING_CERT_FILE_NAME = make_filename('certs', 'signing_cert.pem') -SIGNING_KEY_FILE_NAME = make_filename('private', 'signing_key.pem') -EXAMPLE_TOKENS = ['auth_token_revoked', - 'auth_token_unscoped', - 'auth_token_scoped', - 'auth_token_scoped_expired', - 'auth_v3_token_scoped', - 'auth_v3_token_revoked'] - - -# Helper script to generate the sample data for testing -# the signed tokens using the existing JSON data for the -# MII-prefixed tokens. Uses the keys and certificates -# generated in gen_pki.sh. -def generate_der_form(name): - derfile = make_filename('cms', '%s.der' % name) - with open(derfile, 'w') as f: - derform = cms.cms_sign_data(text, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME, cms.PKIZ_CMS_FORM) - f.write(derform) - -for name in EXAMPLE_TOKENS: - json_file = make_filename('cms', name + '.json') - pkiz_file = make_filename('cms', name + '.pkiz') - with open(json_file, 'r') as f: - string_data = f.read() - - # validate the JSON - try: - token_data = json.loads(string_data) - except ValueError as v: - raise SystemExit('%s while processing token data from %s: %s' % - (v, json_file, string_data)) - - text = json.dumps(token_data).encode('utf-8') - - # Uncomment to record the token uncompressed, - # useful for debugging - # generate_der_form(name) - - encoded = cms.pkiz_sign(text, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME) - - # verify before writing - cms.pkiz_verify(encoded, - SIGNING_CERT_FILE_NAME, - CA_CERT_FILE_NAME) - - with open(pkiz_file, 'w') as f: - f.write(encoded) - - generate_revocation_list() diff --git a/examples/pki/gen_pki.sh b/examples/pki/gen_pki.sh deleted file mode 100755 index 8e2b59f9..00000000 --- a/examples/pki/gen_pki.sh +++ /dev/null @@ -1,208 +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. - -# These functions generate the certificates and signed tokens for the 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 check_openssl { - echo 'Checking openssl availability ...' - which openssl - check_error $? -} - -JSON_FILES="${CMS_DIR}/auth_token_revoked.json ${CMS_DIR}/auth_token_unscoped.json ${CMS_DIR}/auth_token_scoped.json ${CMS_DIR}/auth_token_scoped_expired.json ${CMS_DIR}/revocation_list.json ${CMS_DIR}/auth_v3_token_scoped.json ${CMS_DIR}/auth_v3_token_revoked.json" - -function gen_sample_cms { - for json_file in $JSON_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 -} - diff --git a/examples/pki/private/cakey.pem b/examples/pki/private/cakey.pem deleted file mode 100644 index 1c93ee18..00000000 --- a/examples/pki/private/cakey.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCl8906EaRpibQF -cCBWfxzLi5x/XpZ9iL6UX92NrSJxcDbaGws7s+GtjgDy8UOEonesRWTeqQEZtHpC -3/UHHOnsA8F6ha/pq9LioqT7RehCnZCLBJwh5Ct+lclpWs15SkjJD2LTDkjox0eA -9nOBx+XDlWyU/GAyqx5Wsvg/Kxr0iod9/4IcJdnSdUjq4v0Cxg/zNk08XPJX+F0b -UDhgdUf7JrAmmS5LA8wphRnbIgtVsf6VN9HrbqtHAJDxh8gEfuwdhEW1df1fBtZ+ -6WMIF3IRSbIsZELFB6sqcyRj7HhMoWMkdEyPb2f8mq61MzTgE6lJGIyTRvEoFie7 -qtGADIofAgMBAAECggEBAJ47X3y2xaU7f0KQHsVafgI2JAnuDl+zusOOhJlJs8Wl -0Sc1EgjjAxOQiqcaE96rap//qqYDTuFLjCenkuItV32KNzizr3+GLZWaruRHS6X4 -xpFG2/gUrsQL3fdudOxpP+01lmzW+f25xRvZ4VilWRabquSDntWxA0R3cOwKFbGD -uuwbTw3pBrRfCk/2IdpQtRrvvkVIFiYT6b/zeCQzhp4RETbC0oxqcEEOIUGmimAV -9cbwafinxCo54cOfX4JAh3j7Mp3eQUymoFk5gnmIeVe0QmpH2VkN7eItrhEvHKOk -On7a5xvQ8s3wqPV5ZawHQcqar/p3QnGkiT6a+8LkIMECgYEA2iJ2DprTGZFRN0M7 -Yj4WLsSC3/GKK8eYsKG3TvMrmPqUDaiWLIvBoc1Le59x9eoF7Mha+WX+cAFL+GTg -1sB+PUZZStpf1R1tGvMldvpQ+5GplUBpuQe4J0n5rCG6+5jkvSr7xO+G1B+C3GFq -KR3iltiW5WJRVwh2k8yGvx3agyUCgYEAwsKFX82F7O+9IVud1JSQWmZMiyEK+DEX -JRnwx4HBuWr+AZqbb0grRRb6x8JTUOD4T7DZGxTaAdfzzRjKU2sBAO8VCgaj2Auv -5nsbvfXvrmDDCqwoaD2PMy+kgFvE0QTh65tzuGXl1IgpIYSC1JwnP6kOeUDbqE+k -UXzfVZzDdvMCgYByk9dfJIPt0h7O4Em4+NO+DQqRhtYE2PqjDM60cZZc7IIICp2X -GHHFA4i6jq3Vde9WyIbAqYpUWtoExzgylTm6BdGxN7NOxf4hQcZUEHepLIHfG85s -mlloibrTZ4RH06+SjZlhgE9Z7JNYHvMcVc5HXc0k/9ep15AxYiUFDjFQ4QKBgG7i -k089U4/X2wWgBNdgkmN1tQTNllJCmNvdzhG41dQ8j0vYe8C7BS+76qJLCGaW/6lX -lfRuRcUg78UI5UDjPloKxR7FMwmxdb+yvdPEr2bH3qQ36nWW/u30pSMTnJYownwD -MLp/AYCk2U4lBNwJ3+rF1ODCRY2pcnOWtg0nSL5zAoGAWRoOinogEnOodJzO7eB3 -TmL6M9QMyrAPBDsCnduJ8yW5mMUNod139YbSDxZPYwTLhK/GiHP/7OvLV5hg0s4s -QKnNaMeEowX7dyEO4ehnbfzysxXPKLRVhWhN6MCUc71NMxqr7QkuCXAjJS6/G21+ -Im3+Xb3Scq+UZghR+jiEZF0= ------END PRIVATE KEY----- diff --git a/examples/pki/private/signing_key.pem b/examples/pki/private/signing_key.pem deleted file mode 100644 index 758c0ffe..00000000 --- a/examples/pki/private/signing_key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDM+VrILLl962VH -S8EKWVzdkaOy0OoxGZ63gajM7VTm8AbgtVnYibIOnVZQuz1XbftIGNXPFhYNUypr -LnMXrEEsnxgD4PvU/4bETG+stdricX6d1oKqsNFNR7F7zImiR/OzGhp7dONwccxf -kfX4QHA5Ogso+XMfSdC72SRDszeCeGUcjuo/w2WSLW95SuVvcZLqE/pk3Q2TkCZ1 -8hvNfLoln43QpC469a7srUXATqOJ2mPNvL6E/wOyPefmAoCoG44lFoR3k2jZjBEI -hstJxmH7XgvqErBzpcWd29dms8xz5PNwYdns9CIfb3GaHvQ6r5RTl37/avDrGHOW -KOoD01xLAgMBAAECggEAaIi22qWsh+JYCW9B6NRAPyN6V8Sh2x6UykOO4cwb45b/ -+vOh+YPn0fo9vfhvxTnq0A8SY4WBA5SpanYK7kTEDEyqw7em1y7l/RB6V5t7IMb+ -6uIuS3zXkVEB3AApJSEK0Ql7/gBTydHPh+H5jnzWfujyLhhhtNBBarvH+drZcWio -lWx8RERN4cH+3DZD/xxjH2Ff+X1XMvb8Xcup7MlWi2FtREg7LttLNWNK25iWjciP -QwfWQIrURRJrD2IrOr9V2nuIEvRqRRBoO+pxJT2sC48NJ3hiKV2GtSQe2nRpQJ47 -f9MEsF5KVQOOn+aQ60EKOI0MpNPmpiCZ5hFvBrNuOQKBgQD6vueEdI9eJgz5YN+t -XWdpNippv35RTD8R4bQcE6GqIUXOmtQFS2wPJLn7nisZUsGMNEs36Yl0T9iow63r -5GNAfgzpqN1XZqaSMwAdxKmlBNYpAkVXHhv+1jN+9diDYmoj9T+3Q6Zvk5e/Liyp -6i+TsDppwmmr2utWajhyJ7owFwKBgQDRROncTztGDYLfRcrIoYsPo79KQ8tqwd2a -07Usch2kplTqojCUmmhMMFgV2eZPPiCjnEy2bAYh9I/oj7xG6EwApXTshZdCpivC -rbUV64MakRTUP8IvM6PdI+apkJRsRUi/bSyIbcRlvEoCMNZhfj/5VY6w/jlwrPJj -oBOCXBlB7QKBgQDGEbEeX1i03UfYYh6uep7qbEAaooqsu5cCkBDPMO6+TmQvLPyY -Zhio6bEEQs/2w/lhwBk+xHqw5zXVMiWbtiB03F1k4eBeXxbrW+AWo7gCQ4zMfh+6 -Dm284wVwn9D1D/OaDevT31uEvcjb2ySq3/PPLSEnU8xXVaoa6/NEsX8Q5wKBgQCm -2smULWBXZKJ6n00mVxdnqun0rsVcI6Mrta14+KwGAdEnG5achdivFsTE924YtLKV -gSPxN4RUQokTprc52jHvOf1WMNYAADpYCOSfy55G6nKvIP8VX5lB00Qw4uRUx5FP -gB7H0K2NaGmiAYqNRXqAtOUG3kyyOFMzeAjWIdTJqQKBgQCHzY1c7sS1vv7mPEkr -6CpwoaEbZeFnWoHBA8Rd82psqfYsVJIRwk5Id8zgDSEmoEi8hQ9UrYbrFpLK77xq -EYSxLQHTNlM0G3lyEsv/gJhwYYhdTYiW3Cx3F6Y++jyn9O/+hFMyQvuesAL7DUYE -ptEfvzFprpQUpByXkIpuJub6fg== ------END PRIVATE KEY----- diff --git a/examples/pki/private/ssl_key.pem b/examples/pki/private/ssl_key.pem deleted file mode 100644 index 363ce94b..00000000 --- a/examples/pki/private/ssl_key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL06AaJROwHPgJ -9tcySSBepzJ81jYars2sMvLjyuvdiIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rp -v8dGDIDsxZQVjT/4SLaQUOeDM+9bfkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLY -Wso0SJD0vAi1gmGDlSM/mmhhHTpCDGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1Zrs -lPC5lFvlHD7KBBf6IU2A8Xh/dUa3p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYR -R45pPCVkk6vFsy6P0JwwpnkszB+LcK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4 -YEPirGGrAgMBAAECggEATwvbY0hNwlb5uqOIAXBqpUqiQdexU9fG26lGmSDxKBDv -9o5frcRgBDrMWwvDCgY+HT4CAvB9kJx4/qnpVjkzJp/ZNiJ5VIiehIlbv348rXbh -xkk+bz5dDATCFOXuu1fwL2FhyM5anwhMAav0DyK1VLQ3jGzr9GO6L8hqAn+bQFFu -6ngiODwfhBMl5aRoL9UOBEhccK07znrH0JGRz+3+5Cdz59Xw91Bv210LhNNDL58+ -0JD0N+YztVOQd2bgwo0bQbOEijzmYq+0mjoqAnJh1/++y7PlIPs0AnPgqSnFPx9+ -6FsQEVRgk5Uq3kvPLaP4nT2y6MDZSp+ujYldvJhyQQKBgQDuX2pZIJMZ4aFnkG+K -TmJ5wsLa/u9an0TmvAL9RLtBpVpQNKD8cQ+y8PUZavXDbAIt5NWqZVnTbCR79Dnd -mZKblwcHhtsyA5f89el5KcxY2BREWdHdTnJpNd7XRlUECmzvX1zGj77lA982PhII -yflRBRV3vqLkgC8vfoYgRyRElwKBgQDa5jnLdx/RahfYMOgn1HE5o4hMzLR4Y0Dd -+gELshcUbPqouoP5zOb8WOagVJIgZVOSN+/VqbilVYrqRiNTn2rnoxs+HHRdaJNN -3eXllD4J2HfC2BIj1xSpIdyh2XewAJqw9IToHNB29QUhxOtgwseHciPG6JaKH2ik -kqGKH/EKDQKBgFFAftygiOPCkCTgC9UmANUmOQsy6N2H+pF3tsEj43xt44oBVnqW -A1boYXNnjRwuvdNs9BPf9i1l6E3EItFRXrLgWQoMwryakv0ryYh+YeRKyyW9RBbe -fYs1TJ8unx4Ae79gTxxztQsVNcmkgLs0NWKTjAzEE3w14V+cDhYEie1DAoGBAJdI -V5cLrBzBstsB6eBlDR9lqrRRIUS2a8U9m+1mVlcSfiWQSdehSd4K3tDdwePLw3ch -W4qR8n+pYAlLEe0gFvUhn5lMdwt7U5qUCeehjUKmrRYm2FqWsbu2IFJnBjXIJSC4 -zQXRrC0aZ0KQYpAL7XPpaVp1slyhGmPqxuO78Y0dAoGBAMHo3EIMwu9rfuGwFodr -GFsOZhfJqgo5GDNxxf89Q9WWpMDTCdX+wdBTrN/wsMbBuwIDHrUuRnk6D5CWRjSk -/ikCgHN3kOtrbL8zzqRomGAIIWKYGFEIGe1GHVGo5r//HXHdPxFXygvruQ/xbOA4 -RGvmDiji8vVDq7Shho8I6KuT ------END PRIVATE KEY----- diff --git a/examples/pki/run_all.sh b/examples/pki/run_all.sh deleted file mode 100755 index 2438ec7c..00000000 --- a/examples/pki/run_all.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -x - -# 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. - -. gen_pki.sh - -check_openssl -rm_old -cleanup -setup -generate_ca -ssl_cert_req -cms_signing_cert_req -issue_certs -gen_sample_cms -cleanup diff --git a/keystoneclient/__init__.py b/keystoneclient/__init__.py deleted file mode 100644 index e8ef58eb..00000000 --- a/keystoneclient/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# 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. - -"""The python bindings for the OpenStack Identity (Keystone) project. - -A Client object will allow you to communicate with the Identity server. The -recommended way to get a Client object is to use -:py:func:`keystoneclient.client.Client()`. :py:func:`~.Client()` uses version -discovery to create a V3 or V2 client depending on what versions the Identity -server supports and what version is requested. - -Identity V2 and V3 clients can also be created directly. See -:py:class:`keystoneclient.v3.client.Client` for the V3 client and -:py:class:`keystoneclient.v2_0.client.Client` for the V2 client. - -""" - -import importlib -import sys - -import pbr.version - - -__version__ = pbr.version.VersionInfo('python-keystoneclient').version_string() - -__all__ = ( - # Modules - 'generic', - 'v2_0', - 'v3', - - # Packages - 'access', - 'client', - 'exceptions', - 'httpclient', - 'service_catalog', -) - - -class _LazyImporter(object): - def __init__(self, module): - self._module = module - - def __getattr__(self, name): - # NB: this is only called until the import has been done. - # These submodules are part of the API without explicit importing, but - # expensive to load, so we load them on-demand rather than up-front. - lazy_submodules = [ - 'access', - 'client', - 'exceptions', - 'generic', - 'httpclient', - 'service_catalog', - 'v2_0', - 'v3', - ] - if name in lazy_submodules: - return importlib.import_module('keystoneclient.%s' % name) - - # Return module attributes like __all__ etc. - return getattr(self._module, name) - - -sys.modules[__name__] = _LazyImporter(sys.modules[__name__]) diff --git a/keystoneclient/_discover.py b/keystoneclient/_discover.py deleted file mode 100644 index 69eed9a9..00000000 --- a/keystoneclient/_discover.py +++ /dev/null @@ -1,333 +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. - -"""The passive components to version discovery. - -The Discover object in discover.py contains functions that can create objects -on your behalf. These functions are not usable from within the keystoneclient -library because you will get dependency resolution issues. - -The Discover object in this file provides the querying components of Discovery. -This includes functions like url_for which allow you to retrieve URLs and the -raw data specified in version discovery responses. -""" - -import logging -import re - -from positional import positional - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -_LOGGER = logging.getLogger(__name__) - - -@positional() -def get_version_data(session, url, authenticated=None): - """Retrieve raw version data from a url.""" - headers = {'Accept': 'application/json'} - - resp = session.get(url, headers=headers, authenticated=authenticated) - - try: - body_resp = resp.json() - except ValueError: # nosec(cjschaef): raise a DiscoveryFailure below - pass - else: - # In the event of querying a root URL we will get back a list of - # available versions. - try: - return body_resp['versions']['values'] - except (KeyError, TypeError): # nosec(cjschaef): attempt to return - # versions dict or query the endpoint or raise a DiscoveryFailure - pass - - # Most servers don't have a 'values' element so accept a simple - # versions dict if available. - try: - return body_resp['versions'] - except KeyError: # nosec(cjschaef): query the endpoint or raise a - # DiscoveryFailure - pass - - # Otherwise if we query an endpoint like /v2.0 then we will get back - # just the one available version. - try: - return [body_resp['version']] - except KeyError: # nosec(cjschaef): raise a DiscoveryFailure - pass - - err_text = resp.text[:50] + '...' if len(resp.text) > 50 else resp.text - msg = _('Invalid Response - Bad version data returned: %s') % err_text - raise exceptions.DiscoveryFailure(msg) - - -def normalize_version_number(version): - """Turn a version representation into a tuple.""" - # trim the v from a 'v2.0' or similar - try: - version = version.lstrip('v') - except AttributeError: # nosec(cjschaef): 'version' is not a str, try a - # different type or raise a TypeError - pass - - # if it's an integer or a numeric as a string then normalize it - # to a string, this ensures 1 decimal point - try: - num = float(version) - except Exception: # nosec(cjschaef): 'version' is not a float, try a - # different type or raise a TypeError - pass - else: - version = str(num) - - # if it's a string (or an integer) from above break it on . - try: - return tuple(map(int, version.split('.'))) - except Exception: # nosec(cjschaef): 'version' is not str (or an int), - # try a different type or raise a TypeError - pass - - # last attempt, maybe it's a list or iterable. - try: - return tuple(map(int, version)) - except Exception: # nosec(cjschaef): 'version' is not an expected type, - # raise a TypeError - pass - - raise TypeError(_('Invalid version specified: %s') % version) - - -def version_match(required, candidate): - """Test that an available version satisfies the required version. - - To be suitable a version must be of the same major version as required - and be at least a match in minor/patch level. - - eg. 3.3 is a match for a required 3.1 but 4.1 is not. - - :param tuple required: the version that must be met. - :param tuple candidate: the version to test against required. - - :returns: True if candidate is suitable False otherwise. - :rtype: bool - """ - # major versions must be the same (e.g. even though v2 is a lower - # version than v3 we can't use it if v2 was requested) - if candidate[0] != required[0]: - return False - - # prevent selecting a minor version less than what is required - if candidate < required: - return False - - return True - - -class Discover(object): - - CURRENT_STATUSES = ('stable', 'current', 'supported') - DEPRECATED_STATUSES = ('deprecated',) - EXPERIMENTAL_STATUSES = ('experimental',) - - @positional() - def __init__(self, session, url, authenticated=None): - self._data = get_version_data(session, url, - authenticated=authenticated) - - def raw_version_data(self, allow_experimental=False, - allow_deprecated=True, allow_unknown=False): - """Get raw version information from URL. - - Raw data indicates that only minimal validation processing is performed - on the data, so what is returned here will be the data in the same - format it was received from the endpoint. - - :param bool allow_experimental: Allow experimental version endpoints. - :param bool allow_deprecated: Allow deprecated version endpoints. - :param bool allow_unknown: Allow endpoints with an unrecognised status. - - :returns: The endpoints returned from the server that match the - criteria. - :rtype: list - """ - versions = [] - for v in self._data: - try: - status = v['status'] - except KeyError: - _LOGGER.warning('Skipping over invalid version data. ' - 'No stability status in version.') - continue - - status = status.lower() - - if status in self.CURRENT_STATUSES: - versions.append(v) - elif status in self.DEPRECATED_STATUSES: - if allow_deprecated: - versions.append(v) - elif status in self.EXPERIMENTAL_STATUSES: - if allow_experimental: - versions.append(v) - elif allow_unknown: - versions.append(v) - - return versions - - def version_data(self, **kwargs): - """Get normalized version data. - - Return version data in a structured way. - - :returns: A list of version data dictionaries sorted by version number. - Each data element in the returned list is a dictionary - consisting of at least: - - :version tuple: The normalized version of the endpoint. - :url str: The url for the endpoint. - :raw_status str: The status as provided by the server - :rtype: list(dict) - """ - if kwargs.pop('unstable', None): - kwargs.setdefault('allow_experimental', True) - kwargs.setdefault('allow_unknown', True) - data = self.raw_version_data(**kwargs) - versions = [] - - for v in data: - try: - version_str = v['id'] - except KeyError: - _LOGGER.info('Skipping invalid version data. Missing ID.') - continue - - try: - links = v['links'] - except KeyError: - _LOGGER.info('Skipping invalid version data. Missing links') - continue - - version_number = normalize_version_number(version_str) - - for link in links: - try: - rel = link['rel'] - url = link['href'] - except (KeyError, TypeError): - _LOGGER.info('Skipping invalid version link. ' - 'Missing link URL or relationship.') - continue - - if rel.lower() == 'self': - break - else: - _LOGGER.info('Skipping invalid version data. ' - 'Missing link to endpoint.') - continue - - versions.append({'version': version_number, - 'url': url, - 'raw_status': v['status']}) - - versions.sort(key=lambda v: v['version']) - return versions - - def data_for(self, version, **kwargs): - """Return endpoint data for a version. - - :param tuple version: The version is always a minimum version in the - same major release as there should be no compatibility issues with - using a version newer than the one asked for. - - :returns: the endpoint data for a URL that matches the required version - (the format is described in version_data) or None if no - match. - :rtype: dict - """ - version = normalize_version_number(version) - version_data = self.version_data(**kwargs) - - for data in reversed(version_data): - if version_match(version, data['version']): - return data - - return None - - def url_for(self, version, **kwargs): - """Get the endpoint url for a version. - - :param tuple version: The version is always a minimum version in the - same major release as there should be no compatibility issues with - using a version newer than the one asked for. - - :returns: The url for the specified version or None if no match. - :rtype: str - """ - data = self.data_for(version, **kwargs) - return data['url'] if data else None - - -class _VersionHacks(object): - """A container to abstract the list of version hacks. - - This could be done as simply a dictionary but is abstracted like this to - make for easier testing. - """ - - def __init__(self): - self._discovery_data = {} - - def add_discover_hack(self, service_type, old, new=''): - """Add a new hack for a service type. - - :param str service_type: The service_type in the catalog. - :param re.RegexObject old: The pattern to use. - :param str new: What to replace the pattern with. - """ - hacks = self._discovery_data.setdefault(service_type, []) - hacks.append((old, new)) - - def get_discover_hack(self, service_type, url): - """Apply the catalog hacks and figure out an unversioned endpoint. - - :param str service_type: the service_type to look up. - :param str url: The original url that came from a service_catalog. - - :returns: Either the unversioned url or the one from the catalog - to try. - """ - for old, new in self._discovery_data.get(service_type, []): - new_string, number_of_subs_made = old.subn(new, url) - if number_of_subs_made > 0: - return new_string - - return url - - -_VERSION_HACKS = _VersionHacks() -_VERSION_HACKS.add_discover_hack('identity', re.compile('/v2.0/?$'), '/') - - -def get_catalog_discover_hack(service_type, url): - """Apply the catalog hacks and figure out an unversioned endpoint. - - This function is internal to keystoneclient. - - :param str service_type: the service_type to look up. - :param str url: The original url that came from a service_catalog. - - :returns: Either the unversioned url or the one from the catalog to try. - """ - return _VERSION_HACKS.get_discover_hack(service_type, url) diff --git a/keystoneclient/access.py b/keystoneclient/access.py deleted file mode 100644 index f8174f61..00000000 --- a/keystoneclient/access.py +++ /dev/null @@ -1,886 +0,0 @@ -# Copyright 2012 Nebula, Inc. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import datetime -import warnings - -from oslo_utils import timeutils - -from keystoneclient.i18n import _ -from keystoneclient import service_catalog - - -# gap, in seconds, to determine whether the given token is about to expire -STALE_TOKEN_DURATION = 30 - - -class AccessInfo(dict): - """Encapsulates a raw authentication token from keystone. - - Provides helper methods for extracting useful values from that token. - - """ - - @classmethod - def factory(cls, resp=None, body=None, region_name=None, auth_token=None, - **kwargs): - """Factory function to create a new AccessInfo object. - - Create AccessInfo object given a successful auth response & body - or a user-provided dict. - - .. warning:: - - Use of the region_name argument is deprecated as of the 1.7.0 - release and may be removed in the 2.0.0 release. - - """ - if region_name: - warnings.warn( - 'Use of the region_name argument is deprecated as of the ' - '1.7.0 release and may be removed in the 2.0.0 release.', - DeprecationWarning) - - if body is not None or len(kwargs): - if AccessInfoV3.is_valid(body, **kwargs): - if resp and not auth_token: - auth_token = resp.headers['X-Subject-Token'] - # NOTE(jamielennox): these return AccessInfo because they - # already have auth_token installed on them. - if body: - if region_name: - body['token']['region_name'] = region_name - return AccessInfoV3(auth_token, **body['token']) - else: - return AccessInfoV3(auth_token, **kwargs) - elif AccessInfoV2.is_valid(body, **kwargs): - if body: - if region_name: - body['access']['region_name'] = region_name - auth_ref = AccessInfoV2(**body['access']) - else: - auth_ref = AccessInfoV2(**kwargs) - else: - raise NotImplementedError(_('Unrecognized auth response')) - else: - auth_ref = AccessInfoV2(**kwargs) - - if auth_token: - auth_ref.auth_token = auth_token - - return auth_ref - - def __init__(self, *args, **kwargs): - super(AccessInfo, self).__init__(*args, **kwargs) - self.service_catalog = service_catalog.ServiceCatalog.factory( - resource_dict=self, region_name=self._region_name) - - @property - def _region_name(self): - return self.get('region_name') - - def will_expire_soon(self, stale_duration=None): - """Determine if expiration is about to occur. - - :returns: true if expiration is within the given duration - :rtype: boolean - - """ - stale_duration = (STALE_TOKEN_DURATION if stale_duration is None - else stale_duration) - norm_expires = timeutils.normalize_time(self.expires) - # (gyee) should we move auth_token.will_expire_soon() to timeutils - # instead of duplicating code here? - soon = (timeutils.utcnow() + datetime.timedelta( - seconds=stale_duration)) - return norm_expires < soon - - @classmethod - def is_valid(cls, body, **kwargs): - """Determine if processing valid v2 or v3 token. - - Validates from the auth body or a user-provided dict. - - :returns: true if auth body matches implementing class - :rtype: boolean - """ - raise NotImplementedError() - - def has_service_catalog(self): - """Return true if the authorization token has a service catalog. - - :returns: boolean - """ - raise NotImplementedError() - - @property - def auth_token(self): - """Return the token_id associated with the auth request. - - To be used in headers for authenticating OpenStack API requests. - - :returns: str - """ - return self['auth_token'] - - @auth_token.setter - def auth_token(self, value): - self['auth_token'] = value - - @auth_token.deleter - def auth_token(self): - try: - del self['auth_token'] - except KeyError: # nosec(cjschaef): 'auth_token' is not in the dict - pass - - @property - def expires(self): - """Return the token expiration (as datetime object). - - :returns: datetime - """ - raise NotImplementedError() - - @property - def issued(self): - """Return the token issue time (as datetime object). - - :returns: datetime - """ - raise NotImplementedError() - - @property - def username(self): - """Return the username associated with the auth request. - - Follows the pattern defined in the V2 API of first looking for 'name', - returning that if available, and falling back to 'username' if name - is unavailable. - - :returns: str - """ - raise NotImplementedError() - - @property - def user_id(self): - """Return the user id associated with the auth request. - - :returns: str - """ - raise NotImplementedError() - - @property - def user_domain_id(self): - """Return the user's domain id associated with the auth request. - - For v2, it always returns 'default' which may be different from the - Keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def user_domain_name(self): - """Return the user's domain name associated with the auth request. - - For v2, it always returns 'Default' which may be different from the - Keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def role_ids(self): - """Return a list of user's role ids associated with the auth request. - - :returns: a list of strings of role ids - """ - raise NotImplementedError() - - @property - def role_names(self): - """Return a list of user's role names associated with the auth request. - - :returns: a list of strings of role names - """ - raise NotImplementedError() - - @property - def domain_name(self): - """Return the domain name associated with the auth request. - - :returns: str or None (if no domain associated with the token) - """ - raise NotImplementedError() - - @property - def domain_id(self): - """Return the domain id associated with the auth request. - - :returns: str or None (if no domain associated with the token) - """ - raise NotImplementedError() - - @property - def project_name(self): - """Return the project name associated with the auth request. - - :returns: str or None (if no project associated with the token) - """ - raise NotImplementedError() - - @property - def tenant_name(self): - """Synonym for project_name.""" - return self.project_name - - @property - def scoped(self): - """Return true if the auth token was scoped. - - Return true if scoped to a tenant(project) or domain, - and contains a populated service catalog. - - .. warning:: - - This is deprecated as of the 1.7.0 release in favor of - project_scoped and may be removed in the 2.0.0 release. - - :returns: bool - """ - raise NotImplementedError() - - @property - def project_scoped(self): - """Return true if the auth token was scoped to a tenant(project). - - :returns: bool - """ - raise NotImplementedError() - - @property - def domain_scoped(self): - """Return true if the auth token was scoped to a domain. - - :returns: bool - """ - raise NotImplementedError() - - @property - def trust_id(self): - """Return the trust id associated with the auth request. - - :returns: str or None (if no trust associated with the token) - """ - raise NotImplementedError() - - @property - def trust_scoped(self): - """Return true if the auth token was scoped from a delegated trust. - - The trust delegation is via the OS-TRUST v3 extension. - - :returns: bool - """ - raise NotImplementedError() - - @property - def trustee_user_id(self): - """Return the trustee user id associated with a trust. - - :returns: str or None (if no trust associated with the token) - """ - raise NotImplementedError() - - @property - def trustor_user_id(self): - """Return the trustor user id associated with a trust. - - :returns: str or None (if no trust associated with the token) - """ - raise NotImplementedError() - - @property - def project_id(self): - """Return the project ID associated with the auth request. - - This returns None if the auth token wasn't scoped to a project. - - :returns: str or None (if no project associated with the token) - """ - raise NotImplementedError() - - @property - def tenant_id(self): - """Synonym for project_id.""" - return self.project_id - - @property - def project_domain_id(self): - """Return the project's domain id associated with the auth request. - - For v2, it returns 'default' if a project is scoped or None which may - be different from the keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def project_domain_name(self): - """Return the project's domain name associated with the auth request. - - For v2, it returns 'Default' if a project is scoped or None which may - be different from the keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def auth_url(self): - """Return a tuple of identity URLs. - - The identity URLs are from publicURL and adminURL for the service - 'identity' from the service catalog associated with the authorization - request. If the authentication request wasn't scoped to a tenant - (project), this property will return None. - - DEPRECATED: this doesn't correctly handle region name. You should fetch - it from the service catalog yourself. This may be removed in the 2.0.0 - release. - - :returns: tuple of urls - """ - raise NotImplementedError() - - @property - def management_url(self): - """Return the first adminURL of the identity endpoint. - - The identity endpoint is from the service catalog - associated with the authorization request, or None if the - authentication request wasn't scoped to a tenant (project). - - DEPRECATED: this doesn't correctly handle region name. You should fetch - it from the service catalog yourself. This may be removed in the 2.0.0 - release. - - :returns: tuple of urls - """ - raise NotImplementedError() - - @property - def version(self): - """Return the version of the auth token from identity service. - - :returns: str - """ - return self.get('version') - - @property - def oauth_access_token_id(self): - """Return the access token ID if OAuth authentication used. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def oauth_consumer_id(self): - """Return the consumer ID if OAuth authentication used. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def is_federated(self): - """Return true if federation was used to get the token. - - :returns: boolean - """ - raise NotImplementedError() - - @property - def audit_id(self): - """Return the audit ID if present. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def audit_chain_id(self): - """Return the audit chain ID if present. - - In the event that a token was rescoped then this ID will be the - :py:attr:`audit_id` of the initial token. Returns None if no value - present. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def initial_audit_id(self): - """The audit ID of the initially requested token. - - This is the :py:attr:`audit_chain_id` if present or the - :py:attr:`audit_id`. - """ - return self.audit_chain_id or self.audit_id - - -class AccessInfoV2(AccessInfo): - """An object for encapsulating raw v2 auth token from identity service.""" - - def __init__(self, *args, **kwargs): - super(AccessInfo, self).__init__(*args, **kwargs) - self.update(version='v2.0') - self.service_catalog = service_catalog.ServiceCatalog.factory( - resource_dict=self, - token=self['token']['id'], - region_name=self._region_name) - - @classmethod - def is_valid(cls, body, **kwargs): - if body: - return 'access' in body - elif kwargs: - return kwargs.get('version') == 'v2.0' - else: - return False - - def has_service_catalog(self): - return 'serviceCatalog' in self - - @AccessInfo.auth_token.getter - def auth_token(self): - try: - return super(AccessInfoV2, self).auth_token - except KeyError: - return self['token']['id'] - - @property - def expires(self): - return timeutils.parse_isotime(self['token']['expires']) - - @property - def issued(self): - return timeutils.parse_isotime(self['token']['issued_at']) - - @property - def username(self): - return self['user'].get('name', self['user'].get('username')) - - @property - def user_id(self): - return self['user']['id'] - - @property - def user_domain_id(self): - return 'default' - - @property - def user_domain_name(self): - return 'Default' - - @property - def role_ids(self): - return self.get('metadata', {}).get('roles', []) - - @property - def role_names(self): - return [r['name'] for r in self['user'].get('roles', [])] - - @property - def domain_name(self): - return None - - @property - def domain_id(self): - return None - - @property - def project_name(self): - try: - tenant_dict = self['token']['tenant'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenant' key in - # token, return the name of the tenant or None - pass - else: - return tenant_dict.get('name') - - # pre grizzly - try: - return self['user']['tenantName'] - except KeyError: # nosec(cjschaef): no 'user' key or 'tenantName' in - # 'user', attempt 'tenantId' or return None - pass - - # pre diablo, keystone only provided a tenantId - try: - return self['token']['tenantId'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenantName' or - # 'tenantId' could be found, return None - pass - - @property - def scoped(self): - """Deprecated as of the 1.7.0 release. - - Use project_scoped instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'scoped is deprecated as of the 1.7.0 release in favor of ' - 'project_scoped and may be removed in the 2.0.0 release.', - DeprecationWarning) - if ('serviceCatalog' in self - and self['serviceCatalog'] - and 'tenant' in self['token']): - return True - return False - - @property - def project_scoped(self): - return 'tenant' in self['token'] - - @property - def domain_scoped(self): - return False - - @property - def trust_id(self): - return self.get('trust', {}).get('id') - - @property - def trust_scoped(self): - return 'trust' in self - - @property - def trustee_user_id(self): - return self.get('trust', {}).get('trustee_user_id') - - @property - def trustor_user_id(self): - # this information is not available in the v2 token bug: #1331882 - return None - - @property - def project_id(self): - try: - tenant_dict = self['token']['tenant'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenant' dict, - # attempt to return 'tenantId' or return None - pass - else: - return tenant_dict.get('id') - - # pre grizzly - try: - return self['user']['tenantId'] - except KeyError: # nosec(cjschaef): no 'user' key or 'tenantId' in - # 'user', attempt to retrieve from 'token' or return None - pass - - # pre diablo - try: - return self['token']['tenantId'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenantId' - # could be found, return None - pass - - @property - def project_domain_id(self): - if self.project_id: - return 'default' - - @property - def project_domain_name(self): - if self.project_id: - return 'Default' - - @property - def auth_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'auth_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='publicURL', - region_name=self._region_name) - else: - return None - - @property - def management_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'management_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='adminURL', - region_name=self._region_name) - else: - return None - - @property - def oauth_access_token_id(self): - return None - - @property - def oauth_consumer_id(self): - return None - - @property - def is_federated(self): - return False - - @property - def audit_id(self): - try: - return self['token'].get('audit_ids', [])[0] - except IndexError: - return None - - @property - def audit_chain_id(self): - try: - return self['token'].get('audit_ids', [])[1] - except IndexError: - return None - - -class AccessInfoV3(AccessInfo): - """An object encapsulating raw v3 auth token from identity service.""" - - def __init__(self, token, *args, **kwargs): - super(AccessInfo, self).__init__(*args, **kwargs) - self.update(version='v3') - self.service_catalog = service_catalog.ServiceCatalog.factory( - resource_dict=self, - token=token, - region_name=self._region_name) - if token: - self.auth_token = token - - @classmethod - def is_valid(cls, body, **kwargs): - if body: - return 'token' in body - elif kwargs: - return kwargs.get('version') == 'v3' - else: - return False - - def has_service_catalog(self): - return 'catalog' in self - - @property - def is_federated(self): - return 'OS-FEDERATION' in self['user'] - - @property - def expires(self): - return timeutils.parse_isotime(self['expires_at']) - - @property - def issued(self): - return timeutils.parse_isotime(self['issued_at']) - - @property - def user_id(self): - return self['user']['id'] - - @property - def user_domain_id(self): - try: - return self['user']['domain']['id'] - except KeyError: - if self.is_federated: - return None - raise - - @property - def user_domain_name(self): - try: - return self['user']['domain']['name'] - except KeyError: - if self.is_federated: - return None - raise - - @property - def role_ids(self): - return [r['id'] for r in self.get('roles', [])] - - @property - def role_names(self): - return [r['name'] for r in self.get('roles', [])] - - @property - def username(self): - return self['user']['name'] - - @property - def domain_name(self): - domain = self.get('domain') - if domain: - return domain['name'] - - @property - def domain_id(self): - domain = self.get('domain') - if domain: - return domain['id'] - - @property - def project_id(self): - project = self.get('project') - if project: - return project['id'] - - @property - def project_domain_id(self): - project = self.get('project') - if project: - return project['domain']['id'] - - @property - def project_domain_name(self): - project = self.get('project') - if project: - return project['domain']['name'] - - @property - def project_name(self): - project = self.get('project') - if project: - return project['name'] - - @property - def scoped(self): - """Deprecated as of the 1.7.0 release. - - Use project_scoped instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'scoped is deprecated as of the 1.7.0 release in favor of ' - 'project_scoped and may be removed in the 2.0.0 release.', - DeprecationWarning) - return ('catalog' in self and self['catalog'] and 'project' in self) - - @property - def project_scoped(self): - return 'project' in self - - @property - def domain_scoped(self): - return 'domain' in self - - @property - def trust_id(self): - return self.get('OS-TRUST:trust', {}).get('id') - - @property - def trust_scoped(self): - return 'OS-TRUST:trust' in self - - @property - def trustee_user_id(self): - return self.get('OS-TRUST:trust', {}).get('trustee_user', {}).get('id') - - @property - def trustor_user_id(self): - return self.get('OS-TRUST:trust', {}).get('trustor_user', {}).get('id') - - @property - def auth_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'auth_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='public', - region_name=self._region_name) - else: - return None - - @property - def management_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'management_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='admin', - region_name=self._region_name) - - else: - return None - - @property - def oauth_access_token_id(self): - return self.get('OS-OAUTH1', {}).get('access_token_id') - - @property - def oauth_consumer_id(self): - return self.get('OS-OAUTH1', {}).get('consumer_id') - - @property - def audit_id(self): - try: - return self.get('audit_ids', [])[0] - except IndexError: - return None - - @property - def audit_chain_id(self): - try: - return self.get('audit_ids', [])[1] - except IndexError: - return None diff --git a/keystoneclient/adapter.py b/keystoneclient/adapter.py deleted file mode 100644 index faa61a69..00000000 --- a/keystoneclient/adapter.py +++ /dev/null @@ -1,223 +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. - -import warnings - -from oslo_serialization import jsonutils -from positional import positional - - -class Adapter(object): - """An instance of a session with local variables. - - A session is a global object that is shared around amongst many clients. It - therefore contains state that is relevant to everyone. There is a lot of - state such as the service type and region_name that are only relevant to a - particular client that is using the session. An adapter provides a wrapper - of client local data around the global session object. - - :param session: The session object to wrap. - :type session: keystoneclient.session.Session - :param str service_type: The default service_type for URL discovery. - :param str service_name: The default service_name for URL discovery. - :param str interface: The default interface for URL discovery. - :param str region_name: The default region_name for URL discovery. - :param str endpoint_override: Always use this endpoint URL for requests - for this client. - :param tuple version: The version that this API targets. - :param auth: An auth plugin to use instead of the session one. - :type auth: keystoneclient.auth.base.BaseAuthPlugin - :param str user_agent: The User-Agent string to set. - :param int connect_retries: the maximum number of retries that should - be attempted for connection errors. - Default None - use session default which - is don't retry. - :param logger: A logging object to use for requests that pass through this - adapter. - :type logger: logging.Logger - """ - - @positional() - def __init__(self, session, service_type=None, service_name=None, - interface=None, region_name=None, endpoint_override=None, - version=None, auth=None, user_agent=None, - connect_retries=None, logger=None): - warnings.warn( - 'keystoneclient.adapter.Adapter is deprecated as of the 2.1.0 ' - 'release in favor of keystoneauth1.adapter.Adapter. It will be ' - 'removed in future releases.', DeprecationWarning) - - # NOTE(jamielennox): when adding new parameters to adapter please also - # add them to the adapter call in httpclient.HTTPClient.__init__ - self.session = session - self.service_type = service_type - self.service_name = service_name - self.interface = interface - self.region_name = region_name - self.endpoint_override = endpoint_override - self.version = version - self.user_agent = user_agent - self.auth = auth - self.connect_retries = connect_retries - self.logger = logger - - def _set_endpoint_filter_kwargs(self, kwargs): - if self.service_type: - kwargs.setdefault('service_type', self.service_type) - if self.service_name: - kwargs.setdefault('service_name', self.service_name) - if self.interface: - kwargs.setdefault('interface', self.interface) - if self.region_name: - kwargs.setdefault('region_name', self.region_name) - if self.version: - kwargs.setdefault('version', self.version) - - def request(self, url, method, **kwargs): - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - self._set_endpoint_filter_kwargs(endpoint_filter) - - if self.endpoint_override: - kwargs.setdefault('endpoint_override', self.endpoint_override) - - if self.auth: - kwargs.setdefault('auth', self.auth) - if self.user_agent: - kwargs.setdefault('user_agent', self.user_agent) - if self.connect_retries is not None: - kwargs.setdefault('connect_retries', self.connect_retries) - if self.logger: - kwargs.setdefault('logger', self.logger) - - return self.session.request(url, method, **kwargs) - - def get_token(self, auth=None): - """Return a token as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: :class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - - :returns: A valid token. - :rtype: string - """ - return self.session.get_token(auth or self.auth) - - def get_endpoint(self, auth=None, **kwargs): - """Get an endpoint as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin on - the session. (optional) - :type auth: :class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - :returns: An endpoint if available or None. - :rtype: string - """ - if self.endpoint_override: - return self.endpoint_override - - self._set_endpoint_filter_kwargs(kwargs) - return self.session.get_endpoint(auth or self.auth, **kwargs) - - def invalidate(self, auth=None): - """Invalidate an authentication plugin.""" - return self.session.invalidate(auth or self.auth) - - def get_user_id(self, auth=None): - """Return the authenticated user_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns: Current `user_id` or None if not supported by plugin. - :rtype: string - """ - return self.session.get_user_id(auth or self.auth) - - def get_project_id(self, auth=None): - """Return the authenticated project_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns: Current `project_id` or None if not supported by plugin. - :rtype: string - """ - return self.session.get_project_id(auth or self.auth) - - def get(self, url, **kwargs): - return self.request(url, 'GET', **kwargs) - - def head(self, url, **kwargs): - return self.request(url, 'HEAD', **kwargs) - - def post(self, url, **kwargs): - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - return self.request(url, 'PUT', **kwargs) - - def patch(self, url, **kwargs): - return self.request(url, 'PATCH', **kwargs) - - def delete(self, url, **kwargs): - return self.request(url, 'DELETE', **kwargs) - - -class LegacyJsonAdapter(Adapter): - """Make something that looks like an old HTTPClient. - - A common case when using an adapter is that we want an interface similar to - the HTTPClients of old which returned the body as JSON as well. - - You probably don't want this if you are starting from scratch. - """ - - def request(self, *args, **kwargs): - headers = kwargs.setdefault('headers', {}) - headers.setdefault('Accept', 'application/json') - - try: - kwargs['json'] = kwargs.pop('body') - except KeyError: # nosec(cjschaef): kwargs doesn't contain a 'body' - # key, while 'json' is an optional argument for Session.request - pass - - resp = super(LegacyJsonAdapter, self).request(*args, **kwargs) - - body = None - if resp.text: - try: - body = jsonutils.loads(resp.text) - except ValueError: # nosec(cjschaef): return None for body as - # expected - pass - - return resp, body diff --git a/keystoneclient/auth/__init__.py b/keystoneclient/auth/__init__.py deleted file mode 100644 index eeae768f..00000000 --- a/keystoneclient/auth/__init__.py +++ /dev/null @@ -1,38 +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.auth.base import * # noqa -from keystoneclient.auth.cli import * # noqa -from keystoneclient.auth.conf import * # noqa - - -__all__ = ( - # auth.base - 'AUTH_INTERFACE', - 'BaseAuthPlugin', - 'get_available_plugin_names', - 'get_available_plugin_classes', - 'get_plugin_class', - 'IDENTITY_AUTH_HEADER_NAME', - 'PLUGIN_NAMESPACE', - - # auth.cli - 'load_from_argparse_arguments', - 'register_argparse_arguments', - - # auth.conf - 'get_common_conf_options', - 'get_plugin_options', - 'load_from_conf_options', - 'register_conf_options', -) diff --git a/keystoneclient/auth/base.py b/keystoneclient/auth/base.py deleted file mode 100644 index 0036b8cf..00000000 --- a/keystoneclient/auth/base.py +++ /dev/null @@ -1,374 +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. - -import os - -from debtcollector import removals -from keystoneauth1 import plugin -import six -import stevedore - -from keystoneclient import exceptions - - -# NOTE(jamielennox): The AUTH_INTERFACE is a special value that can be -# requested from get_endpoint. If a plugin receives this as the value of -# 'interface' it should return the initial URL that was passed to the plugin. -AUTH_INTERFACE = plugin.AUTH_INTERFACE - -PLUGIN_NAMESPACE = 'keystoneclient.auth.plugin' -IDENTITY_AUTH_HEADER_NAME = 'X-Auth-Token' - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_available_plugin_names(): - """Get the names of all the plugins that are available on the system. - - This is particularly useful for help and error text to prompt a user for - example what plugins they may specify. - - :returns: A list of names. - :rtype: frozenset - """ - mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, - invoke_on_load=False) - return frozenset(mgr.names()) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_available_plugin_classes(): - """Retrieve all the plugin classes available on the system. - - :returns: A dict with plugin entrypoint name as the key and the plugin - class as the value. - :rtype: dict - """ - mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, - propagate_map_exceptions=True, - invoke_on_load=False) - - return dict(mgr.map(lambda ext: (ext.entry_point.name, ext.plugin))) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_plugin_class(name): - """Retrieve a plugin class by its entrypoint name. - - :param str name: The name of the object to get. - - :returns: An auth plugin class. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - try: - mgr = stevedore.DriverManager(namespace=PLUGIN_NAMESPACE, - name=name, - invoke_on_load=False) - except RuntimeError: - raise exceptions.NoMatchingPlugin(name) - - return mgr.driver - - -class BaseAuthPlugin(object): - """The basic structure of an authentication plugin.""" - - def get_token(self, session, **kwargs): - """Obtain a token. - - How the token is obtained is up to the plugin. If it is still valid - it may be re-used, retrieved from cache or invoke an authentication - request against a server. - - There are no required kwargs. They are passed directly to the auth - plugin and they are implementation specific. - - Returning None will indicate that no token was able to be retrieved. - - This function is misplaced as it should only be required for auth - plugins that use the 'X-Auth-Token' header. However due to the way - plugins evolved this method is required and often called to trigger an - authentication request on a new plugin. - - When implementing a new plugin it is advised that you implement this - method, however if you don't require the 'X-Auth-Token' header override - the `get_headers` method instead. - - :param session: A session object so the plugin can make HTTP calls. - :type session: keystoneclient.session.Session - - :return: A token to use. - :rtype: string - """ - return None - - def get_headers(self, session, **kwargs): - """Fetch authentication headers for message. - - This is a more generalized replacement of the older get_token to allow - plugins to specify different or additional authentication headers to - the OpenStack standard 'X-Auth-Token' header. - - How the authentication headers are obtained is up to the plugin. If the - headers are still valid they may be re-used, retrieved from cache or - the plugin may invoke an authentication request against a server. - - The default implementation of get_headers calls the `get_token` method - to enable older style plugins to continue functioning unchanged. - Subclasses should feel free to completely override this function to - provide the headers that they want. - - There are no required kwargs. They are passed directly to the auth - plugin and they are implementation specific. - - Returning None will indicate that no token was able to be retrieved and - that authorization was a failure. Adding no authentication data can be - achieved by returning an empty dictionary. - - :param session: The session object that the auth_plugin belongs to. - :type session: keystoneclient.session.Session - - :returns: Headers that are set to authenticate a message or None for - failure. Note that when checking this value that the empty - dict is a valid, non-failure response. - :rtype: dict - """ - token = self.get_token(session) - - if not token: - return None - - return {IDENTITY_AUTH_HEADER_NAME: token} - - def get_endpoint(self, session, **kwargs): - """Return an endpoint for the client. - - There are no required keyword arguments to ``get_endpoint`` as a plugin - implementation should use best effort with the information available to - determine the endpoint. However there are certain standard options that - will be generated by the clients and should be used by plugins: - - - ``service_type``: what sort of service is required. - - ``service_name``: the name of the service in the catalog. - - ``interface``: what visibility the endpoint should have. - - ``region_name``: the region the endpoint exists in. - - :param session: The session object that the auth_plugin belongs to. - :type session: keystoneclient.session.Session - - :returns: The base URL that will be used to talk to the required - service or None if not available. - :rtype: string - """ - return None - - def get_connection_params(self, session, **kwargs): - """Return any additional connection parameters required for the plugin. - - :param session: The session object that the auth_plugin belongs to. - :type session: keystoneclient.session.Session - - :returns: Headers that are set to authenticate a message or None for - failure. Note that when checking this value that the empty - dict is a valid, non-failure response. - :rtype: dict - """ - return {} - - def invalidate(self): - """Invalidate the current authentication data. - - This should result in fetching a new token on next call. - - A plugin may be invalidated if an Unauthorized HTTP response is - returned to indicate that the token may have been revoked or is - otherwise now invalid. - - :returns: True if there was something that the plugin did to - invalidate. This means that it makes sense to try again. If - nothing happens returns False to indicate give up. - :rtype: bool - """ - return False - - def get_user_id(self, session, **kwargs): - """Return a unique user identifier of the plugin. - - Wherever possible the user id should be inferred from the token however - there are certain URLs and other places that require access to the - currently authenticated user id. - - :param session: A session object so the plugin can make HTTP calls. - :type session: keystoneclient.session.Session - - :returns: A user identifier or None if one is not available. - :rtype: str - """ - return None - - def get_project_id(self, session, **kwargs): - """Return the project id that we are authenticated to. - - Wherever possible the project id should be inferred from the token - however there are certain URLs and other places that require access to - the currently authenticated project id. - - :param session: A session object so the plugin can make HTTP calls. - :type session: keystoneclient.session.Session - - :returns: A project identifier or None if one is not available. - :rtype: str - """ - return None - - @classmethod - def get_options(cls): - """Return the list of parameters associated with the auth plugin. - - This list may be used to generate CLI or config arguments. - - :returns: A list of Param objects describing available plugin - parameters. - :rtype: List - """ - return [] - - @classmethod - def load_from_options(cls, **kwargs): - """Create a plugin from the arguments retrieved from get_options. - - A client can override this function to do argument validation or to - handle differences between the registered options and what is required - to create the plugin. - """ - return cls(**kwargs) - - @classmethod - def register_argparse_arguments(cls, parser): - """Register the CLI options provided by a specific plugin. - - Given a plugin class convert it's options into argparse arguments and - add them to a parser. - - :param parser: the parser to attach argparse options. - :type parser: argparse.ArgumentParser - """ - # NOTE(jamielennox): ideally oslo_config would be smart enough to - # handle all the Opt manipulation that goes on in this file. However it - # is currently not. Options are handled in as similar a way as - # possible to oslo_config such that when available we should be able to - # transition. - - for opt in cls.get_options(): - args = [] - envs = [] - - for o in [opt] + opt.deprecated_opts: - args.append('--os-%s' % o.name) - envs.append('OS_%s' % o.name.replace('-', '_').upper()) - - # select the first ENV that is not false-y or return None - env_vars = (os.environ.get(e) for e in envs) - default = six.next(six.moves.filter(None, env_vars), None) - - parser.add_argument(*args, - default=default or opt.default, - metavar=opt.metavar, - help=opt.help, - dest='os_%s' % opt.dest) - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - """Load a specific plugin object from an argparse result. - - Convert the results of a parse into the specified plugin. - - :param namespace: The result from CLI parsing. - :type namespace: argparse.Namespace - - :returns: An auth plugin, or None if a name is not provided. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - """ - def _getter(opt): - return getattr(namespace, 'os_%s' % opt.dest) - - return cls.load_from_options_getter(_getter, **kwargs) - - @classmethod - def register_conf_options(cls, conf, group): - """Register the oslo_config options that are needed for a plugin. - - :param conf: A config object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - """ - plugin_opts = cls.get_options() - conf.register_opts(plugin_opts, group=group) - - @classmethod - def load_from_conf_options(cls, conf, group, **kwargs): - """Load the plugin from a CONF object. - - Convert the options already registered into a real plugin. - - :param conf: A config object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - - :returns: An authentication Plugin. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - """ - def _getter(opt): - return conf[group][opt.dest] - - return cls.load_from_options_getter(_getter, **kwargs) - - @classmethod - def load_from_options_getter(cls, getter, **kwargs): - """Load a plugin from a getter function returning appropriate values. - - To handle cases other than the provided CONF and CLI loading you can - specify a custom loader function that will be queried for the option - value. - - The getter is a function that takes one value, an - :py:class:`oslo_config.cfg.Opt` and returns a value to load with. - - :param getter: A function that returns a value for the given opt. - :type getter: callable - - :returns: An authentication Plugin. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - """ - plugin_opts = cls.get_options() - - for opt in plugin_opts: - val = getter(opt) - if val is not None: - val = opt.type(val) - kwargs.setdefault(opt.dest, val) - - return cls.load_from_options(**kwargs) diff --git a/keystoneclient/auth/cli.py b/keystoneclient/auth/cli.py deleted file mode 100644 index 1b8e0543..00000000 --- a/keystoneclient/auth/cli.py +++ /dev/null @@ -1,97 +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. - -import argparse -import os - -from debtcollector import removals -from positional import positional - -from keystoneclient.auth import base - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -@positional() -def register_argparse_arguments(parser, argv, default=None): - """Register CLI options needed to create a plugin. - - The function inspects the provided arguments so that it can also register - the options required for that specific plugin if available. - - :param argparse.ArgumentParser: the parser to attach argparse options to. - :param List argv: the arguments provided to the application. - :param str/class default: a default plugin name or a plugin object to use - if one isn't specified by the CLI. default: None. - - :returns: The plugin class that will be loaded or None if not provided. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - in_parser = argparse.ArgumentParser(add_help=False) - env_plugin = os.environ.get('OS_AUTH_PLUGIN', default) - for p in (in_parser, parser): - p.add_argument('--os-auth-plugin', - metavar='', - default=env_plugin, - help='The auth plugin to load') - - options, _args = in_parser.parse_known_args(argv) - - if not options.os_auth_plugin: - return None - - if isinstance(options.os_auth_plugin, type): - msg = 'Default Authentication options' - plugin = options.os_auth_plugin - else: - msg = 'Options specific to the %s plugin.' % options.os_auth_plugin - plugin = base.get_plugin_class(options.os_auth_plugin) - - group = parser.add_argument_group('Authentication Options', msg) - plugin.register_argparse_arguments(group) - return plugin - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def load_from_argparse_arguments(namespace, **kwargs): - """Retrieve the created plugin from the completed argparse results. - - Loads and creates the auth plugin from the information parsed from the - command line by argparse. - - :param Namespace namespace: The result from CLI parsing. - - :returns: An auth plugin, or None if a name is not provided. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - if not namespace.os_auth_plugin: - return None - - if isinstance(namespace.os_auth_plugin, type): - plugin = namespace.os_auth_plugin - else: - plugin = base.get_plugin_class(namespace.os_auth_plugin) - - return plugin.load_from_argparse_arguments(namespace, **kwargs) diff --git a/keystoneclient/auth/conf.py b/keystoneclient/auth/conf.py deleted file mode 100644 index ca3cbcf8..00000000 --- a/keystoneclient/auth/conf.py +++ /dev/null @@ -1,132 +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 debtcollector import removals -from oslo_config import cfg - -from keystoneclient.auth import base - -_AUTH_PLUGIN_OPT = cfg.StrOpt('auth_plugin', help='Name of the plugin to load') - -_section_help = 'Config Section from which to load plugin specific options' -_AUTH_SECTION_OPT = cfg.StrOpt('auth_section', help=_section_help) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_common_conf_options(): - """Get the oslo_config options common for all auth plugins. - - These may be useful without being registered for config file generation - or to manipulate the options before registering them yourself. - - The options that are set are: - :auth_plugin: The name of the plugin to load. - :auth_section: The config file section to load options from. - - :returns: A list of oslo_config options. - """ - return [_AUTH_PLUGIN_OPT, _AUTH_SECTION_OPT] - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_plugin_options(name): - """Get the oslo_config options for a specific plugin. - - This will be the list of config options that is registered and loaded by - the specified plugin. - - :returns: A list of oslo_config options. - """ - return base.get_plugin_class(name).get_options() - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def register_conf_options(conf, group): - """Register the oslo_config options that are needed for a plugin. - - This only registers the basic options shared by all plugins. Options that - are specific to a plugin are loaded just before they are read. - - The defined options are: - - - auth_plugin: the name of the auth plugin that will be used for - authentication. - - auth_section: the group from which further auth plugin options should be - taken. If section is not provided then the auth plugin options will be - taken from the same group as provided in the parameters. - - :param conf: config object to register with. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The ini group to register options in. - """ - conf.register_opt(_AUTH_SECTION_OPT, group=group) - - # NOTE(jamielennox): plugins are allowed to specify a 'section' which is - # the group that auth options should be taken from. If not present they - # come from the same as the base options were registered in. If present - # then the auth_plugin option may be read from that section so add that - # option. - if conf[group].auth_section: - group = conf[group].auth_section - - conf.register_opt(_AUTH_PLUGIN_OPT, group=group) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def load_from_conf_options(conf, group, **kwargs): - """Load a plugin from an oslo_config CONF object. - - Each plugin will register their own required options and so there is no - standard list and the plugin should be consulted. - - The base options should have been registered with register_conf_options - before this function is called. - - :param conf: A conf object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - - :returns: An authentication Plugin or None if a name is not provided - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - # NOTE(jamielennox): plugins are allowed to specify a 'section' which is - # the group that auth options should be taken from. If not present they - # come from the same as the base options were registered in. - if conf[group].auth_section: - group = conf[group].auth_section - - name = conf[group].auth_plugin - if not name: - return None - - plugin_class = base.get_plugin_class(name) - plugin_class.register_conf_options(conf, group) - return plugin_class.load_from_conf_options(conf, group, **kwargs) diff --git a/keystoneclient/auth/identity/__init__.py b/keystoneclient/auth/identity/__init__.py deleted file mode 100644 index 8146c1e5..00000000 --- a/keystoneclient/auth/identity/__init__.py +++ /dev/null @@ -1,37 +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.auth.identity import base -from keystoneclient.auth.identity import generic -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 - - -BaseIdentityPlugin = base.BaseIdentityPlugin - -V2Password = v2.Password -V2Token = v2.Token - -V3Password = v3.Password -V3Token = v3.Token - -Password = generic.Password -Token = generic.Token - - -__all__ = ('BaseIdentityPlugin', - 'Password', - 'Token', - 'V2Password', - 'V2Token', - 'V3Password', - 'V3Token') diff --git a/keystoneclient/auth/identity/access.py b/keystoneclient/auth/identity/access.py deleted file mode 100644 index 5849b757..00000000 --- a/keystoneclient/auth/identity/access.py +++ /dev/null @@ -1,48 +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 positional import positional - -from keystoneclient.auth.identity import base - - -class AccessInfoPlugin(base.BaseIdentityPlugin): - """A plugin that turns an existing AccessInfo object into a usable plugin. - - There are cases where reuse of an auth_ref or AccessInfo object is - warranted such as from a cache, from auth_token middleware, or another - source. - - Turn the existing access info object into an identity plugin. This plugin - cannot be refreshed as the AccessInfo object does not contain any - authorizing information. - - :param auth_ref: the existing AccessInfo object. - :type auth_ref: keystoneclient.access.AccessInfo - :param auth_url: the url where this AccessInfo was retrieved from. Required - if using the AUTH_INTERFACE with get_endpoint. (optional) - """ - - @positional() - def __init__(self, auth_ref, auth_url=None): - super(AccessInfoPlugin, self).__init__(auth_url=auth_url, - reauthenticate=False) - self.auth_ref = auth_ref - - def get_auth_ref(self, session, **kwargs): - return self.auth_ref - - def invalidate(self): - # NOTE(jamielennox): Don't allow the default invalidation to occur - # because on next authentication request we will only get the same - # auth_ref object again. - return False diff --git a/keystoneclient/auth/identity/base.py b/keystoneclient/auth/identity/base.py deleted file mode 100644 index b20d3e27..00000000 --- a/keystoneclient/auth/identity/base.py +++ /dev/null @@ -1,422 +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. - -import abc -import logging -import threading -import warnings - -from oslo_config import cfg -from positional import positional -import six - -from keystoneclient import _discover -from keystoneclient.auth import base -from keystoneclient import exceptions - -LOG = logging.getLogger(__name__) - - -def get_options(): - return [ - cfg.StrOpt('auth-url', help='Authentication URL'), - ] - - -@six.add_metaclass(abc.ABCMeta) -class BaseIdentityPlugin(base.BaseAuthPlugin): - - # we count a token as valid (not needing refreshing) if it is valid for at - # least this many seconds before the token expiry time - MIN_TOKEN_LIFE_SECONDS = 120 - - def __init__(self, - auth_url=None, - username=None, - password=None, - token=None, - trust_id=None, - reauthenticate=True): - - super(BaseIdentityPlugin, self).__init__() - - warnings.warn( - 'keystoneclient auth plugins are deprecated as of the 2.1.0 ' - 'release in favor of keystoneauth1 plugins. They will be removed ' - 'in future releases.', DeprecationWarning) - - self.auth_url = auth_url - self.auth_ref = None - self.reauthenticate = reauthenticate - - self._endpoint_cache = {} - self._lock = threading.Lock() - - self._username = username - self._password = password - self._token = token - self._trust_id = trust_id - - @property - def username(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'username is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._username - - @username.setter - def username(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'username is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._username = value - - @property - def password(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'password is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._password - - @password.setter - def password(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'password is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._password = value - - @property - def token(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'token is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._token - - @token.setter - def token(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'token is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._token = value - - @property - def trust_id(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'trust_id is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'trust_id is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._trust_id = value - - @abc.abstractmethod - def get_auth_ref(self, session, **kwargs): - """Obtain a token from an OpenStack Identity Service. - - This method is overridden by the various token version plugins. - - This method should not be called independently and is expected to be - invoked via the do_authenticate() method. - - This method will be invoked if the AccessInfo object cached by the - plugin is not valid. Thus plugins should always fetch a new AccessInfo - when invoked. If you are looking to just retrieve the current auth data - then you should use get_access(). - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.InvalidResponse: The response - returned wasn't - appropriate. - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :returns: Token access information. - :rtype: :py:class:`keystoneclient.access.AccessInfo` - """ - pass # pragma: no cover - - def get_token(self, session, **kwargs): - """Return a valid auth token. - - If a valid token is not present then a new one will be fetched. - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :return: A valid token. - :rtype: string - """ - return self.get_access(session).auth_token - - def _needs_reauthenticate(self): - """Return if the existing token needs to be re-authenticated. - - The token should be refreshed if it is about to expire. - - :returns: True if the plugin should fetch a new token. False otherwise. - """ - if not self.auth_ref: - # authentication was never fetched. - return True - - if not self.reauthenticate: - # don't re-authenticate if it has been disallowed. - return False - - if self.auth_ref.will_expire_soon(self.MIN_TOKEN_LIFE_SECONDS): - # if it's about to expire we should re-authenticate now. - return True - - # otherwise it's fine and use the existing one. - return False - - def get_access(self, session, **kwargs): - """Fetch or return a current AccessInfo object. - - If a valid AccessInfo is present then it is returned otherwise a new - one will be fetched. - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :returns: Valid AccessInfo - :rtype: :py:class:`keystoneclient.access.AccessInfo` - """ - # Hey Kids! Thread safety is important particularly in the case where - # a service is creating an admin style plugin that will then proceed - # to make calls from many threads. As a token expires all the threads - # will try and fetch a new token at once, so we want to ensure that - # only one thread tries to actually fetch from keystone at once. - with self._lock: - if self._needs_reauthenticate(): - self.auth_ref = self.get_auth_ref(session) - - return self.auth_ref - - def invalidate(self): - """Invalidate the current authentication data. - - This should result in fetching a new token on next call. - - A plugin may be invalidated if an Unauthorized HTTP response is - returned to indicate that the token may have been revoked or is - otherwise now invalid. - - :returns: True if there was something that the plugin did to - invalidate. This means that it makes sense to try again. If - nothing happens returns False to indicate give up. - :rtype: bool - """ - if self.auth_ref: - self.auth_ref = None - return True - - return False - - def get_endpoint(self, session, service_type=None, interface=None, - region_name=None, service_name=None, version=None, - **kwargs): - """Return a valid endpoint for a service. - - If a valid token is not present then a new one will be fetched using - the session and kwargs. - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - :param string service_type: The type of service to lookup the endpoint - for. This plugin will return None (failure) - if service_type is not provided. - :param string interface: The exposure of the endpoint. Should be - `public`, `internal`, `admin`, or `auth`. - `auth` is special here to use the `auth_url` - rather than a URL extracted from the service - catalog. Defaults to `public`. - :param string region_name: The region the endpoint should exist in. - (optional) - :param string service_name: The name of the service in the catalog. - (optional) - :param tuple version: The minimum version number required for this - endpoint. (optional) - - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :return: A valid endpoint URL or None if not available. - :rtype: string or None - """ - # NOTE(jamielennox): if you specifically ask for requests to be sent to - # the auth url then we can ignore many of the checks. Typically if you - # are asking for the auth endpoint it means that there is no catalog to - # query however we still need to support asking for a specific version - # of the auth_url for generic plugins. - if interface is base.AUTH_INTERFACE: - url = self.auth_url - service_type = service_type or 'identity' - - else: - if not service_type: - LOG.warning( - 'Plugin cannot return an endpoint without knowing the ' - 'service type that is required. Add service_type to ' - 'endpoint filtering data.') - return None - - if not interface: - interface = 'public' - - service_catalog = self.get_access(session).service_catalog - url = service_catalog.url_for(service_type=service_type, - endpoint_type=interface, - region_name=region_name, - service_name=service_name) - - if not version: - # NOTE(jamielennox): This may not be the best thing to default to - # but is here for backwards compatibility. It may be worth - # defaulting to the most recent version. - return url - - # NOTE(jamielennox): For backwards compatibility people might have a - # versioned endpoint in their catalog even though they want to use - # other endpoint versions. So we support a list of client defined - # situations where we can strip the version component from a URL before - # doing discovery. - hacked_url = _discover.get_catalog_discover_hack(service_type, url) - - try: - disc = self.get_discovery(session, hacked_url, authenticated=False) - except (exceptions.DiscoveryFailure, - exceptions.HTTPError, - exceptions.ConnectionError): - # NOTE(jamielennox): Again if we can't contact the server we fall - # back to just returning the URL from the catalog. This may not be - # the best default but we need it for now. - LOG.warning( - 'Failed to contact the endpoint at %s for discovery. Fallback ' - 'to using that endpoint as the base url.', url) - else: - url = disc.url_for(version) - - return url - - def get_user_id(self, session, **kwargs): - return self.get_access(session).user_id - - def get_project_id(self, session, **kwargs): - return self.get_access(session).project_id - - @positional() - def get_discovery(self, session, url, authenticated=None): - """Return the discovery object for a URL. - - Check the session and the plugin cache to see if we have already - performed discovery on the URL and if so return it, otherwise create - a new discovery object, cache it and return it. - - This function is expected to be used by subclasses and should not - be needed by users. - - :param session: A session object to discover with. - :type session: keystoneclient.session.Session - :param str url: The url to lookup. - :param bool authenticated: Include a token in the discovery call. - (optional) Defaults to None (use a token - if a plugin is installed). - - :raises keystoneclient.exceptions.DiscoveryFailure: if for some reason - the lookup fails. - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :returns: A discovery object with the results of looking up that URL. - """ - # NOTE(jamielennox): we want to cache endpoints on the session as well - # so that they maintain sharing between auth plugins. Create a cache on - # the session if it doesn't exist already. - try: - session_endpoint_cache = session._identity_endpoint_cache - except AttributeError: - session_endpoint_cache = session._identity_endpoint_cache = {} - - # NOTE(jamielennox): There is a cache located on both the session - # object and the auth plugin object so that they can be shared and the - # cache is still usable - for cache in (self._endpoint_cache, session_endpoint_cache): - disc = cache.get(url) - - if disc: - break - else: - disc = _discover.Discover(session, url, - authenticated=authenticated) - self._endpoint_cache[url] = disc - session_endpoint_cache[url] = disc - - return disc - - @classmethod - def get_options(cls): - options = super(BaseIdentityPlugin, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneclient/auth/identity/generic/__init__.py b/keystoneclient/auth/identity/generic/__init__.py deleted file mode 100644 index a96fb979..00000000 --- a/keystoneclient/auth/identity/generic/__init__.py +++ /dev/null @@ -1,21 +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.auth.identity.generic.base import BaseGenericPlugin # noqa -from keystoneclient.auth.identity.generic.password import Password # noqa -from keystoneclient.auth.identity.generic.token import Token # noqa - - -__all__ = ('BaseGenericPlugin', - 'Password', - 'Token', - ) diff --git a/keystoneclient/auth/identity/generic/base.py b/keystoneclient/auth/identity/generic/base.py deleted file mode 100644 index 98680ef9..00000000 --- a/keystoneclient/auth/identity/generic/base.py +++ /dev/null @@ -1,192 +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. - -import abc -import logging - -from oslo_config import cfg -import six -import six.moves.urllib.parse as urlparse - -from keystoneclient import _discover -from keystoneclient.auth.identity import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -LOG = logging.getLogger(__name__) - - -def get_options(): - return [ - cfg.StrOpt('domain-id', help='Domain ID to scope to'), - cfg.StrOpt('domain-name', help='Domain name to scope to'), - cfg.StrOpt('tenant-id', help='Tenant ID to scope to'), - cfg.StrOpt('tenant-name', help='Tenant name to scope to'), - cfg.StrOpt('project-id', help='Project ID to scope to'), - cfg.StrOpt('project-name', help='Project name to scope to'), - cfg.StrOpt('project-domain-id', - help='Domain ID containing project'), - cfg.StrOpt('project-domain-name', - help='Domain name containing project'), - cfg.StrOpt('trust-id', help='Trust ID'), - ] - - -@six.add_metaclass(abc.ABCMeta) -class BaseGenericPlugin(base.BaseIdentityPlugin): - """An identity plugin that is not version dependent. - - Internally we will construct a version dependent plugin with the resolved - URL and then proxy all calls from the base plugin to the versioned one. - """ - - def __init__(self, auth_url, - tenant_id=None, - tenant_name=None, - project_id=None, - project_name=None, - project_domain_id=None, - project_domain_name=None, - domain_id=None, - domain_name=None, - trust_id=None): - super(BaseGenericPlugin, self).__init__(auth_url=auth_url) - - self._project_id = project_id or tenant_id - self._project_name = project_name or tenant_name - self._project_domain_id = project_domain_id - self._project_domain_name = project_domain_name - self._domain_id = domain_id - self._domain_name = domain_name - self._trust_id = trust_id - - self._plugin = None - - @property - def trust_id(self): - # Override to remove deprecation. - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - # Override to remove deprecation. - self._trust_id = value - - @abc.abstractmethod - def create_plugin(self, session, version, url, raw_status=None): - """Create a plugin from the given parameters. - - This function will be called multiple times with the version and url - of a potential endpoint. If a plugin can be constructed that fits the - params then it should return it. If not return None and then another - call will be made with other available URLs. - - :param session: A session object. - :type session: keystoneclient.session.Session - :param tuple version: A tuple of the API version at the URL. - :param string url: The base URL for this version. - :param string raw_status: The status that was in the discovery field. - - :returns: A plugin that can match the parameters or None if nothing. - """ - return None # pragma: no cover - - @property - def _has_domain_scope(self): - """Are there domain parameters. - - Domain parameters are v3 only so returns if any are set. - - :returns: True if a domain parameter is set, false otherwise. - """ - return any([self._domain_id, self._domain_name, - self._project_domain_id, self._project_domain_name]) - - @property - def _v2_params(self): - """Return parameters that are common to v2 plugins.""" - return {'trust_id': self._trust_id, - 'tenant_id': self._project_id, - 'tenant_name': self._project_name} - - @property - def _v3_params(self): - """Return parameters that are common to v3 plugins.""" - return {'trust_id': self._trust_id, - 'project_id': self._project_id, - 'project_name': self._project_name, - 'project_domain_id': self._project_domain_id, - 'project_domain_name': self._project_domain_name, - 'domain_id': self._domain_id, - 'domain_name': self._domain_name} - - def _do_create_plugin(self, session): - plugin = None - - try: - disc = self.get_discovery(session, - self.auth_url, - authenticated=False) - except (exceptions.DiscoveryFailure, - exceptions.HTTPError, - exceptions.ConnectionError): - LOG.warning('Discovering versions from the identity service ' - 'failed when creating the password plugin. ' - 'Attempting to determine version from URL.') - - url_parts = urlparse.urlparse(self.auth_url) - path = url_parts.path.lower() - - if path.startswith('/v2.0') and not self._has_domain_scope: - plugin = self.create_plugin(session, (2, 0), self.auth_url) - elif path.startswith('/v3'): - plugin = self.create_plugin(session, (3, 0), self.auth_url) - - else: - disc_data = disc.version_data() - - for data in disc_data: - version = data['version'] - - if (_discover.version_match((2,), version) and - self._has_domain_scope): - # NOTE(jamielennox): if there are domain parameters there - # is no point even trying against v2 APIs. - continue - - plugin = self.create_plugin(session, - version, - data['url'], - raw_status=data['raw_status']) - - if plugin: - break - - if plugin: - return plugin - - # so there were no URLs that i could use for auth of any version. - msg = _('Could not determine a suitable URL for the plugin') - raise exceptions.DiscoveryFailure(msg) - - def get_auth_ref(self, session, **kwargs): - if not self._plugin: - self._plugin = self._do_create_plugin(session) - - return self._plugin.get_auth_ref(session, **kwargs) - - @classmethod - def get_options(cls): - options = super(BaseGenericPlugin, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneclient/auth/identity/generic/cli.py b/keystoneclient/auth/identity/generic/cli.py deleted file mode 100644 index 9debf631..00000000 --- a/keystoneclient/auth/identity/generic/cli.py +++ /dev/null @@ -1,84 +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 oslo_config import cfg -from positional import positional - -from keystoneclient.auth.identity.generic import password -from keystoneclient import exceptions as exc -from keystoneclient.i18n import _ - - -class DefaultCLI(password.Password): - """A Plugin that provides typical authentication options for CLIs. - - This plugin provides standard username and password authentication options - as well as allowing users to override with a custom token and endpoint. - """ - - @positional() - def __init__(self, endpoint=None, token=None, **kwargs): - super(DefaultCLI, self).__init__(**kwargs) - - self._token = token - self._endpoint = endpoint - - @classmethod - def get_options(cls): - options = super(DefaultCLI, cls).get_options() - options.extend([cfg.StrOpt('endpoint', - help='A URL to use instead of a catalog'), - cfg.StrOpt('token', - secret=True, - help='Always use the specified token')]) - return options - - def get_token(self, *args, **kwargs): - if self._token: - return self._token - - return super(DefaultCLI, self).get_token(*args, **kwargs) - - def get_endpoint(self, *args, **kwargs): - if self._endpoint: - return self._endpoint - - return super(DefaultCLI, self).get_endpoint(*args, **kwargs) - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - token = kwargs.get('token') or namespace.os_token - endpoint = kwargs.get('endpoint') or namespace.os_endpoint - auth_url = kwargs.get('auth_url') or namespace.os_auth_url - - if token and not endpoint: - # if a user provides a token then they must also provide an - # endpoint because we aren't fetching a token to get a catalog from - msg = _('A service URL must be provided with a token') - raise exc.CommandError(msg) - elif (not token) and (not auth_url): - # if you don't provide a token you are going to provide at least an - # auth_url with which to authenticate. - raise exc.CommandError(_('Expecting an auth URL via either ' - '--os-auth-url or env[OS_AUTH_URL]')) - - plugin = super(DefaultCLI, cls).load_from_argparse_arguments(namespace, - **kwargs) - - if (not token) and (not plugin._password): - # we do this after the load so that the base plugin has an - # opportunity to prompt the user for a password - raise exc.CommandError(_('Expecting a password provided via ' - 'either --os-password, env[OS_PASSWORD], ' - 'or prompted response')) - - return plugin diff --git a/keystoneclient/auth/identity/generic/password.py b/keystoneclient/auth/identity/generic/password.py deleted file mode 100644 index 873e2539..00000000 --- a/keystoneclient/auth/identity/generic/password.py +++ /dev/null @@ -1,89 +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 oslo_config import cfg -from positional import positional - -from keystoneclient import _discover -from keystoneclient.auth.identity.generic import base -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 -from keystoneclient import utils - - -def get_options(): - return [ - cfg.StrOpt('user-id', help='User id'), - cfg.StrOpt('username', dest='username', help='Username', - deprecated_name='user-name'), - cfg.StrOpt('user-domain-id', help="User's domain id"), - cfg.StrOpt('user-domain-name', help="User's domain name"), - cfg.StrOpt('password', secret=True, help="User's password"), - ] - - -class Password(base.BaseGenericPlugin): - """A common user/password authentication plugin. - - :param string username: Username for authentication. - :param string user_id: User ID for authentication. - :param string password: Password for authentication. - :param string user_domain_id: User's domain ID for authentication. - :param string user_domain_name: User's domain name for authentication. - - """ - - @positional() - def __init__(self, auth_url, username=None, user_id=None, password=None, - user_domain_id=None, user_domain_name=None, **kwargs): - super(Password, self).__init__(auth_url=auth_url, **kwargs) - - self._username = username - self._user_id = user_id - self._password = password - self._user_domain_id = user_domain_id - self._user_domain_name = user_domain_name - - def create_plugin(self, session, version, url, raw_status=None): - if _discover.version_match((2,), version): - if self._user_domain_id or self._user_domain_name: - # If you specify any domain parameters it won't work so quit. - return None - - return v2.Password(auth_url=url, - user_id=self._user_id, - username=self._username, - password=self._password, - **self._v2_params) - - elif _discover.version_match((3,), version): - return v3.Password(auth_url=url, - user_id=self._user_id, - username=self._username, - user_domain_id=self._user_domain_id, - user_domain_name=self._user_domain_name, - password=self._password, - **self._v3_params) - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - options.extend(get_options()) - return options - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - if not (kwargs.get('password') or namespace.os_password): - kwargs['password'] = utils.prompt_user_password() - - return super(Password, cls).load_from_argparse_arguments(namespace, - **kwargs) diff --git a/keystoneclient/auth/identity/generic/token.py b/keystoneclient/auth/identity/generic/token.py deleted file mode 100644 index e3d01aa0..00000000 --- a/keystoneclient/auth/identity/generic/token.py +++ /dev/null @@ -1,48 +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 oslo_config import cfg - -from keystoneclient import _discover -from keystoneclient.auth.identity.generic import base -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 - - -def get_options(): - return [ - cfg.StrOpt('token', secret=True, help='Token to authenticate with'), - ] - - -class Token(base.BaseGenericPlugin): - """Generic token auth plugin. - - :param string token: Token for authentication. - """ - - def __init__(self, auth_url, token=None, **kwargs): - super(Token, self).__init__(auth_url, **kwargs) - self._token = token - - def create_plugin(self, session, version, url, raw_status=None): - if _discover.version_match((2,), version): - return v2.Token(url, self._token, **self._v2_params) - - elif _discover.version_match((3,), version): - return v3.Token(url, self._token, **self._v3_params) - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneclient/auth/identity/v2.py b/keystoneclient/auth/identity/v2.py deleted file mode 100644 index 6a403dcd..00000000 --- a/keystoneclient/auth/identity/v2.py +++ /dev/null @@ -1,242 +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. - -import abc -import logging - -from oslo_config import cfg -from positional import positional -import six - -from keystoneclient import access -from keystoneclient.auth.identity import base -from keystoneclient import exceptions -from keystoneclient import utils - -_logger = logging.getLogger(__name__) - - -@six.add_metaclass(abc.ABCMeta) -class Auth(base.BaseIdentityPlugin): - """Identity V2 Authentication Plugin. - - :param string auth_url: Identity service endpoint for authorization. - :param string trust_id: Trust ID for trust scoping. - :param string tenant_id: Tenant ID for project scoping. - :param string tenant_name: Tenant name for project scoping. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - @classmethod - def get_options(cls): - options = super(Auth, cls).get_options() - - options.extend([ - cfg.StrOpt('tenant-id', help='Tenant ID'), - cfg.StrOpt('tenant-name', help='Tenant Name'), - cfg.StrOpt('trust-id', help='Trust ID'), - ]) - - return options - - @positional() - def __init__(self, auth_url, - trust_id=None, - tenant_id=None, - tenant_name=None, - reauthenticate=True): - super(Auth, self).__init__(auth_url=auth_url, - reauthenticate=reauthenticate) - - self._trust_id = trust_id - self.tenant_id = tenant_id - self.tenant_name = tenant_name - - @property - def trust_id(self): - # Override to remove deprecation. - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - # Override to remove deprecation. - self._trust_id = value - - def get_auth_ref(self, session, **kwargs): - headers = {'Accept': 'application/json'} - url = self.auth_url.rstrip('/') + '/tokens' - params = {'auth': self.get_auth_data(headers)} - - if self.tenant_id: - params['auth']['tenantId'] = self.tenant_id - elif self.tenant_name: - params['auth']['tenantName'] = self.tenant_name - if self.trust_id: - params['auth']['trust_id'] = self.trust_id - - _logger.debug('Making authentication request to %s', url) - resp = session.post(url, json=params, headers=headers, - authenticated=False, log=False) - - try: - resp_data = resp.json()['access'] - except (KeyError, ValueError): - raise exceptions.InvalidResponse(response=resp) - - return access.AccessInfoV2(**resp_data) - - @abc.abstractmethod - def get_auth_data(self, headers=None): - """Return the authentication section of an auth plugin. - - :param dict headers: The headers that will be sent with the auth - request if a plugin needs to add to them. - :return: A dict of authentication data for the auth type. - :rtype: dict - """ - pass # pragma: no cover - - -_NOT_PASSED = object() - - -class Password(Auth): - """A plugin for authenticating with a username and password. - - A username or user_id must be provided. - - :param string auth_url: Identity service endpoint for authorization. - :param string username: Username for authentication. - :param string password: Password for authentication. - :param string user_id: User ID for authentication. - :param string trust_id: Trust ID for trust scoping. - :param string tenant_id: Tenant ID for tenant scoping. - :param string tenant_name: Tenant name for tenant scoping. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - - :raises TypeError: if a user_id or username is not provided. - """ - - @positional(4) - def __init__(self, auth_url, username=_NOT_PASSED, password=None, - user_id=_NOT_PASSED, **kwargs): - super(Password, self).__init__(auth_url, **kwargs) - - if username is _NOT_PASSED and user_id is _NOT_PASSED: - msg = 'You need to specify either a username or user_id' - raise TypeError(msg) - - if username is _NOT_PASSED: - username = None - if user_id is _NOT_PASSED: - user_id = None - - self.user_id = user_id - self._username = username - self._password = password - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - def get_auth_data(self, headers=None): - auth = {'password': self.password} - - if self.username: - auth['username'] = self.username - elif self.user_id: - auth['userId'] = self.user_id - - return {'passwordCredentials': auth} - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - if not (kwargs.get('password') or namespace.os_password): - kwargs['password'] = utils.prompt_user_password() - - return super(Password, cls).load_from_argparse_arguments(namespace, - **kwargs) - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - - options.extend([ - cfg.StrOpt('username', - dest='username', - deprecated_name='user-name', - help='Username to login with'), - cfg.StrOpt('user-id', help='User ID to login with'), - cfg.StrOpt('password', secret=True, help='Password to use'), - ]) - - return options - - -class Token(Auth): - """A plugin for authenticating with an existing token. - - :param string auth_url: Identity service endpoint for authorization. - :param string token: Existing token for authentication. - :param string tenant_id: Tenant ID for tenant scoping. - :param string tenant_name: Tenant name for tenant scoping. - :param string trust_id: Trust ID for trust scoping. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - def __init__(self, auth_url, token, **kwargs): - super(Token, self).__init__(auth_url, **kwargs) - self._token = token - - @property - def token(self): - # Override to remove deprecation. - return self._token - - @token.setter - def token(self, value): - # Override to remove deprecation. - self._token = value - - def get_auth_data(self, headers=None): - if headers is not None: - headers['X-Auth-Token'] = self.token - return {'token': {'id': self.token}} - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('token', secret=True, help='Token'), - ]) - - return options diff --git a/keystoneclient/auth/identity/v3/__init__.py b/keystoneclient/auth/identity/v3/__init__.py deleted file mode 100644 index f25bf5e2..00000000 --- a/keystoneclient/auth/identity/v3/__init__.py +++ /dev/null @@ -1,30 +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.auth.identity.v3.base import * # noqa -from keystoneclient.auth.identity.v3.federated import * # noqa -from keystoneclient.auth.identity.v3.password import * # noqa -from keystoneclient.auth.identity.v3.token import * # noqa - - -__all__ = ('Auth', - 'AuthConstructor', - 'AuthMethod', - 'BaseAuth', - - 'FederatedBaseAuth', - - 'Password', - 'PasswordMethod', - - 'Token', - 'TokenMethod') diff --git a/keystoneclient/auth/identity/v3/base.py b/keystoneclient/auth/identity/v3/base.py deleted file mode 100644 index 3576045a..00000000 --- a/keystoneclient/auth/identity/v3/base.py +++ /dev/null @@ -1,265 +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. - -import abc -import json -import logging - -from oslo_config import cfg -from positional import positional -import six - -from keystoneclient import access -from keystoneclient.auth.identity import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - -_logger = logging.getLogger(__name__) - -__all__ = ('Auth', 'AuthMethod', 'AuthConstructor', 'BaseAuth') - - -@six.add_metaclass(abc.ABCMeta) -class BaseAuth(base.BaseIdentityPlugin): - """Identity V3 Authentication Plugin. - - :param string auth_url: Identity service endpoint for authentication. - :param List auth_methods: A collection of methods to authenticate with. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - :param bool include_catalog: Include the service catalog in the returned - token. (optional) default True. - """ - - @positional() - def __init__(self, auth_url, - trust_id=None, - domain_id=None, - domain_name=None, - project_id=None, - project_name=None, - project_domain_id=None, - project_domain_name=None, - reauthenticate=True, - include_catalog=True): - super(BaseAuth, self).__init__(auth_url=auth_url, - reauthenticate=reauthenticate) - self._trust_id = trust_id - self.domain_id = domain_id - self.domain_name = domain_name - self.project_id = project_id - self.project_name = project_name - self.project_domain_id = project_domain_id - self.project_domain_name = project_domain_name - self.include_catalog = include_catalog - - @property - def trust_id(self): - # Override to remove deprecation. - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - # Override to remove deprecation. - self._trust_id = value - - @property - def token_url(self): - """The full URL where we will send authentication data.""" - return '%s/auth/tokens' % self.auth_url.rstrip('/') - - @abc.abstractmethod - def get_auth_ref(self, session, **kwargs): - return None # pragma: no cover - - @classmethod - def get_options(cls): - options = super(BaseAuth, cls).get_options() - - options.extend([ - cfg.StrOpt('domain-id', help='Domain ID to scope to'), - cfg.StrOpt('domain-name', help='Domain name to scope to'), - cfg.StrOpt('project-id', help='Project ID to scope to'), - cfg.StrOpt('project-name', help='Project name to scope to'), - cfg.StrOpt('project-domain-id', - help='Domain ID containing project'), - cfg.StrOpt('project-domain-name', - help='Domain name containing project'), - cfg.StrOpt('trust-id', help='Trust ID'), - ]) - - return options - - -class Auth(BaseAuth): - """Identity V3 Authentication Plugin. - - :param string auth_url: Identity service endpoint for authentication. - :param List auth_methods: A collection of methods to authenticate with. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - :param bool include_catalog: Include the service catalog in the returned - token. (optional) default True. - :param bool unscoped: Force the return of an unscoped token. This will make - the keystone server return an unscoped token even if - a default_project_id is set for this user. - """ - - def __init__(self, auth_url, auth_methods, **kwargs): - self.unscoped = kwargs.pop('unscoped', False) - super(Auth, self).__init__(auth_url=auth_url, **kwargs) - self.auth_methods = auth_methods - - def get_auth_ref(self, session, **kwargs): - headers = {'Accept': 'application/json'} - body = {'auth': {'identity': {}}} - ident = body['auth']['identity'] - rkwargs = {} - - for method in self.auth_methods: - name, auth_data = method.get_auth_data(session, - self, - headers, - request_kwargs=rkwargs) - ident.setdefault('methods', []).append(name) - ident[name] = auth_data - - if not ident: - raise exceptions.AuthorizationFailure( - _('Authentication method required (e.g. password)')) - - mutual_exclusion = [bool(self.domain_id or self.domain_name), - bool(self.project_id or self.project_name), - bool(self.trust_id), - bool(self.unscoped)] - - if sum(mutual_exclusion) > 1: - raise exceptions.AuthorizationFailure( - _('Authentication cannot be scoped to multiple targets. Pick ' - 'one of: project, domain, trust or unscoped')) - - if self.domain_id: - body['auth']['scope'] = {'domain': {'id': self.domain_id}} - elif self.domain_name: - body['auth']['scope'] = {'domain': {'name': self.domain_name}} - elif self.project_id: - body['auth']['scope'] = {'project': {'id': self.project_id}} - elif self.project_name: - scope = body['auth']['scope'] = {'project': {}} - scope['project']['name'] = self.project_name - - if self.project_domain_id: - scope['project']['domain'] = {'id': self.project_domain_id} - elif self.project_domain_name: - scope['project']['domain'] = {'name': self.project_domain_name} - elif self.trust_id: - body['auth']['scope'] = {'OS-TRUST:trust': {'id': self.trust_id}} - elif self.unscoped: - body['auth']['scope'] = {'unscoped': {}} - - # NOTE(jamielennox): we add nocatalog here rather than in token_url - # directly as some federation plugins require the base token_url - token_url = self.token_url - if not self.include_catalog: - token_url += '?nocatalog' - - _logger.debug('Making authentication request to %s', token_url) - resp = session.post(token_url, json=body, headers=headers, - authenticated=False, log=False, **rkwargs) - - try: - _logger.debug(json.dumps(resp.json())) - resp_data = resp.json()['token'] - except (KeyError, ValueError): - raise exceptions.InvalidResponse(response=resp) - - return access.AccessInfoV3(resp.headers['X-Subject-Token'], - **resp_data) - - -@six.add_metaclass(abc.ABCMeta) -class AuthMethod(object): - """One part of a V3 Authentication strategy. - - V3 Tokens allow multiple methods to be presented when authentication - against the server. Each one of these methods is implemented by an - AuthMethod. - - Note: When implementing an AuthMethod use the method_parameters - and do not use positional arguments. Otherwise they can't be picked up by - the factory method and don't work as well with AuthConstructors. - """ - - _method_parameters = [] - - def __init__(self, **kwargs): - for param in self._method_parameters: - setattr(self, param, kwargs.pop(param, None)) - - if kwargs: - msg = _("Unexpected Attributes: %s") % ", ".join(kwargs) - raise AttributeError(msg) - - @classmethod - def _extract_kwargs(cls, kwargs): - """Remove parameters related to this method from other kwargs.""" - return dict([(p, kwargs.pop(p, None)) - for p in cls._method_parameters]) - - @abc.abstractmethod - def get_auth_data(self, session, auth, headers, **kwargs): - """Return the authentication section of an auth plugin. - - :param session: The communication session. - :type session: keystoneclient.session.Session - :param base.Auth auth: The auth plugin calling the method. - :param dict headers: The headers that will be sent with the auth - request if a plugin needs to add to them. - :return: The identifier of this plugin and a dict of authentication - data for the auth type. - :rtype: tuple(string, dict) - """ - pass # pragma: no cover - - -@six.add_metaclass(abc.ABCMeta) -class AuthConstructor(Auth): - """Abstract base class for creating an Auth Plugin. - - The Auth Plugin created contains only one authentication method. This - is generally the required usage. - - An AuthConstructor creates an AuthMethod based on the method's - arguments and the auth_method_class defined by the plugin. It then - creates the auth plugin with only that authentication method. - """ - - _auth_method_class = None - - def __init__(self, auth_url, *args, **kwargs): - method_kwargs = self._auth_method_class._extract_kwargs(kwargs) - method = self._auth_method_class(*args, **method_kwargs) - super(AuthConstructor, self).__init__(auth_url, [method], **kwargs) diff --git a/keystoneclient/auth/identity/v3/federated.py b/keystoneclient/auth/identity/v3/federated.py deleted file mode 100644 index 97d83e8f..00000000 --- a/keystoneclient/auth/identity/v3/federated.py +++ /dev/null @@ -1,121 +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. - -import abc - -from oslo_config import cfg -import six - -from keystoneclient.auth.identity.v3 import base -from keystoneclient.auth.identity.v3 import token - -__all__ = ('FederatedBaseAuth',) - - -@six.add_metaclass(abc.ABCMeta) -class FederatedBaseAuth(base.BaseAuth): - - rescoping_plugin = token.Token - - def __init__(self, auth_url, identity_provider, protocol, **kwargs): - """Class constructor for federated authentication plugins. - - Accepting following parameters: - - :param auth_url: URL of the Identity Service - :type auth_url: string - :param identity_provider: Name of the Identity Provider the client - will authenticate against. This parameter - will be used to build a dynamic URL used to - obtain unscoped OpenStack token. - :type identity_provider: string - :param protocol: Protocol name configured on the keystone service - provider side - :type protocol: string - - """ - super(FederatedBaseAuth, self).__init__(auth_url=auth_url, **kwargs) - self.identity_provider = identity_provider - self.protocol = protocol - - @classmethod - def get_options(cls): - options = super(FederatedBaseAuth, cls).get_options() - - options.extend([ - cfg.StrOpt('identity-provider', - help="Identity Provider's name"), - cfg.StrOpt('protocol', help="Name of the federated protocol used " - "for federated authentication. Must " - "match its counterpart name " - "configured at the keystone service " - "provider. Typically values would be " - "'saml2' or 'oidc'.") - ]) - - return options - - @property - def federated_token_url(self): - """Full URL where authorization data is sent.""" - values = { - 'host': self.auth_url.rstrip('/'), - 'identity_provider': self.identity_provider, - 'protocol': self.protocol - } - url = ("%(host)s/OS-FEDERATION/identity_providers/" - "%(identity_provider)s/protocols/%(protocol)s/auth") - url = url % values - - return url - - def _get_scoping_data(self): - return {'trust_id': self.trust_id, - 'domain_id': self.domain_id, - 'domain_name': self.domain_name, - 'project_id': self.project_id, - 'project_name': self.project_name, - 'project_domain_id': self.project_domain_id, - 'project_domain_name': self.project_domain_name} - - def get_auth_ref(self, session, **kwargs): - """Authenticate retrieve token information. - - This is a multi-step process where a client does federated authn - receives an unscoped token. - - If an unscoped token is successfully received and scoping information - is present then the token is rescoped to that target. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: a token data representation - :rtype: :py:class:`keystoneclient.access.AccessInfo` - - """ - auth_ref = self.get_unscoped_auth_ref(session) - scoping = self._get_scoping_data() - - if any(scoping.values()): - token_plugin = self.rescoping_plugin(self.auth_url, - token=auth_ref.auth_token, - **scoping) - - auth_ref = token_plugin.get_auth_ref(session) - - return auth_ref - - @abc.abstractmethod - def get_unscoped_auth_ref(self, session, **kwargs): - """Fetch unscoped federated token.""" - pass # pragma: no cover diff --git a/keystoneclient/auth/identity/v3/password.py b/keystoneclient/auth/identity/v3/password.py deleted file mode 100644 index 99094a1e..00000000 --- a/keystoneclient/auth/identity/v3/password.py +++ /dev/null @@ -1,97 +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 oslo_config import cfg - -from keystoneclient.auth.identity.v3 import base -from keystoneclient import utils - - -__all__ = ('PasswordMethod', 'Password') - - -class PasswordMethod(base.AuthMethod): - """Construct a User/Password based authentication method. - - :param string password: Password for authentication. - :param string username: Username for authentication. - :param string user_id: User ID for authentication. - :param string user_domain_id: User's domain ID for authentication. - :param string user_domain_name: User's domain name for authentication. - """ - - _method_parameters = ['user_id', - 'username', - 'user_domain_id', - 'user_domain_name', - 'password'] - - def get_auth_data(self, session, auth, headers, **kwargs): - user = {'password': self.password} - - if self.user_id: - user['id'] = self.user_id - elif self.username: - user['name'] = self.username - - if self.user_domain_id: - user['domain'] = {'id': self.user_domain_id} - elif self.user_domain_name: - user['domain'] = {'name': self.user_domain_name} - - return 'password', {'user': user} - - -class Password(base.AuthConstructor): - """A plugin for authenticating with a username and password. - - :param string auth_url: Identity service endpoint for authentication. - :param string password: Password for authentication. - :param string username: Username for authentication. - :param string user_id: User ID for authentication. - :param string user_domain_id: User's domain ID for authentication. - :param string user_domain_name: User's domain name for authentication. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - _auth_method_class = PasswordMethod - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - - options.extend([ - cfg.StrOpt('user-id', help='User ID'), - cfg.StrOpt('username', dest='username', help='Username', - deprecated_name='user-name'), - cfg.StrOpt('user-domain-id', help="User's domain id"), - cfg.StrOpt('user-domain-name', help="User's domain name"), - cfg.StrOpt('password', secret=True, help="User's password"), - ]) - - return options - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - if not (kwargs.get('password') or namespace.os_password): - kwargs['password'] = utils.prompt_user_password() - - return super(Password, cls).load_from_argparse_arguments(namespace, - **kwargs) diff --git a/keystoneclient/auth/identity/v3/token.py b/keystoneclient/auth/identity/v3/token.py deleted file mode 100644 index 396a11a2..00000000 --- a/keystoneclient/auth/identity/v3/token.py +++ /dev/null @@ -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. - -from oslo_config import cfg - -from keystoneclient.auth.identity.v3 import base - - -__all__ = ('TokenMethod', 'Token') - - -class TokenMethod(base.AuthMethod): - """Construct an Auth plugin to fetch a token from a token. - - :param string token: Token for authentication. - """ - - _method_parameters = ['token'] - - def get_auth_data(self, session, auth, headers, **kwargs): - headers['X-Auth-Token'] = self.token - return 'token', {'id': self.token} - - -class Token(base.AuthConstructor): - """A plugin for authenticating with an existing Token. - - :param string auth_url: Identity service endpoint for authentication. - :param string token: Token for authentication. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - _auth_method_class = TokenMethod - - def __init__(self, auth_url, token, **kwargs): - super(Token, self).__init__(auth_url, token=token, **kwargs) - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('token', - secret=True, - help='Token to authenticate with'), - ]) - - return options diff --git a/keystoneclient/auth/token_endpoint.py b/keystoneclient/auth/token_endpoint.py deleted file mode 100644 index 6b60f9cb..00000000 --- a/keystoneclient/auth/token_endpoint.py +++ /dev/null @@ -1,62 +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. - -import warnings - -from oslo_config import cfg - -from keystoneclient.auth import base - - -class Token(base.BaseAuthPlugin): - """A provider that will always use the given token and endpoint. - - This is really only useful for testing and in certain CLI cases where you - have a known endpoint and admin token that you want to use. - """ - - def __init__(self, endpoint, token): - # NOTE(jamielennox): endpoint is reserved for when plugins - # can be used to provide that information - warnings.warn( - 'TokenEndpoint plugin is deprecated as of the 2.1.0 release in ' - 'favor of keystoneauth1.token_endpoint.Token. It will be removed ' - 'in future releases.', - DeprecationWarning) - - self.endpoint = endpoint - self.token = token - - def get_token(self, session): - return self.token - - def get_endpoint(self, session, **kwargs): - """Return the supplied endpoint. - - Using this plugin the same endpoint is returned regardless of the - parameters passed to the plugin. - """ - return self.endpoint - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('endpoint', - help='The endpoint that will always be used'), - cfg.StrOpt('token', - secret=True, - help='The token that will always be used'), - ]) - - return options diff --git a/keystoneclient/base.py b/keystoneclient/base.py deleted file mode 100644 index 80e09a0e..00000000 --- a/keystoneclient/base.py +++ /dev/null @@ -1,549 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 OpenStack Foundation -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# 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. - -"""Base utilities to build API operation managers and objects on top of.""" - -import abc -import copy -import functools -import warnings - -from keystoneauth1 import exceptions as ksa_exceptions -from keystoneauth1 import plugin -from oslo_utils import strutils -import six -from six.moves import urllib - -from keystoneclient import exceptions as ksc_exceptions -from keystoneclient.i18n import _ - - -def getid(obj): - """Return id if argument is a Resource. - - Abstracts the common pattern of allowing both an object or an object's ID - (UUID) as a parameter when dealing with relationships. - """ - try: - if obj.uuid: - return obj.uuid - except AttributeError: # nosec(cjschaef): 'obj' doesn't contain attribute - # 'uuid', return attribute 'id' or the 'obj' - pass - try: - return obj.id - except AttributeError: - return obj - - -def filter_none(**kwargs): - """Remove any entries from a dictionary where the value is None.""" - return dict((k, v) for k, v in kwargs.items() if v is not None) - - -def filter_kwargs(f): - @functools.wraps(f) - def func(*args, **kwargs): - new_kwargs = {} - for key, ref in kwargs.items(): - if ref is None: - # drop null values - continue - - id_value = getid(ref) - if id_value != ref: - # If an object with an id was passed, then use the id, e.g.: - # user: user(id=1) becomes user_id: 1 - key = '%s_id' % key - - new_kwargs[key] = id_value - - return f(*args, **new_kwargs) - return func - - -class Manager(object): - """Basic manager type providing common operations. - - Managers interact with a particular type of API (servers, flavors, images, - etc.) and provide CRUD operations for them. - - :param client: instance of BaseClient descendant for HTTP requests - - """ - - resource_class = None - - def __init__(self, client): - super(Manager, self).__init__() - self.client = client - - @property - def api(self): - """The client. - - .. warning:: - - This property is deprecated as of the 1.7.0 release in favor of - :meth:`client` and may be removed in the 2.0.0 release. - - """ - warnings.warn( - 'api is deprecated as of the 1.7.0 release in favor of client and ' - 'may be removed in the 2.0.0 release', DeprecationWarning) - return self.client - - def _list(self, url, response_key, obj_class=None, body=None, **kwargs): - """List the collection. - - :param url: a partial URL, e.g., '/servers' - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param obj_class: class for constructing the returned objects - (self.resource_class will be used by default) - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param kwargs: Additional arguments will be passed to the request. - """ - if body: - resp, body = self.client.post(url, body=body, **kwargs) - else: - resp, body = self.client.get(url, **kwargs) - - if obj_class is None: - obj_class = self.resource_class - - data = body[response_key] - # NOTE(ja): keystone returns values as list as {'values': [ ... ]} - # unlike other services which just return the list... - try: - data = data['values'] - except (KeyError, TypeError): # nosec(cjschaef): keystone data values - # not as expected (see comment above), assumption is that values - # are already returned in a list (so simply utilize that list) - pass - - return [obj_class(self, res, loaded=True) for res in data if res] - - def _get(self, url, response_key, **kwargs): - """Get an object from collection. - - :param url: a partial URL, e.g., '/servers' - :param response_key: the key to be looked up in response dictionary, - e.g., 'server' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.get(url, **kwargs) - return self.resource_class(self, body[response_key], loaded=True) - - def _head(self, url, **kwargs): - """Retrieve request headers for an object. - - :param url: a partial URL, e.g., '/servers' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.head(url, **kwargs) - return resp.status_code == 204 - - def _post(self, url, body, response_key, return_raw=False, **kwargs): - """Create an object. - - :param url: a partial URL, e.g., '/servers' - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param return_raw: flag to force returning raw JSON instead of - Python object of self.resource_class - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.post(url, body=body, **kwargs) - if return_raw: - return body[response_key] - return self.resource_class(self, body[response_key]) - - def _put(self, url, body=None, response_key=None, **kwargs): - """Update an object with PUT method. - - :param url: a partial URL, e.g., '/servers' - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.put(url, body=body, **kwargs) - # PUT requests may not return a body - if body is not None: - if response_key is not None: - return self.resource_class(self, body[response_key]) - else: - return self.resource_class(self, body) - - def _patch(self, url, body=None, response_key=None, **kwargs): - """Update an object with PATCH method. - - :param url: a partial URL, e.g., '/servers' - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.patch(url, body=body, **kwargs) - if response_key is not None: - return self.resource_class(self, body[response_key]) - else: - return self.resource_class(self, body) - - def _delete(self, url, **kwargs): - """Delete an object. - - :param url: a partial URL, e.g., '/servers/my-server' - :param kwargs: Additional arguments will be passed to the request. - """ - return self.client.delete(url, **kwargs) - - def _update(self, url, body=None, response_key=None, method="PUT", - **kwargs): - methods = {"PUT": self.client.put, - "POST": self.client.post, - "PATCH": self.client.patch} - try: - resp, body = methods[method](url, body=body, - **kwargs) - except KeyError: - raise ksc_exceptions.ClientException(_("Invalid update method: %s") - % method) - # PUT requests may not return a body - if body: - return self.resource_class(self, body[response_key]) - - -@six.add_metaclass(abc.ABCMeta) -class ManagerWithFind(Manager): - """Manager with additional `find()`/`findall()` methods.""" - - @abc.abstractmethod - def list(self): - pass # pragma: no cover - - def find(self, **kwargs): - """Find a single item with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - rl = self.findall(**kwargs) - num = len(rl) - - if num == 0: - msg = _("No %(name)s matching %(kwargs)s.") % { - 'name': self.resource_class.__name__, 'kwargs': kwargs} - raise ksa_exceptions.NotFound(404, msg) - elif num > 1: - raise ksc_exceptions.NoUniqueMatch - else: - return rl[0] - - def findall(self, **kwargs): - """Find all items with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - found = [] - searches = kwargs.items() - - for obj in self.list(): - try: - if all(getattr(obj, attr) == value - for (attr, value) in searches): - found.append(obj) - except AttributeError: - continue - - return found - - -class CrudManager(Manager): - """Base manager class for manipulating Keystone entities. - - Children of this class are expected to define a `collection_key` and `key`. - - - `collection_key`: Usually a plural noun by convention (e.g. `entities`); - used to refer collections in both URL's (e.g. `/v3/entities`) and JSON - objects containing a list of member resources (e.g. `{'entities': [{}, - {}, {}]}`). - - `key`: Usually a singular noun by convention (e.g. `entity`); used to - refer to an individual member of the collection. - - """ - - collection_key = None - key = None - base_url = None - - def build_url(self, dict_args_in_out=None): - """Build a resource URL for the given kwargs. - - Given an example collection where `collection_key = 'entities'` and - `key = 'entity'`, the following URL's could be generated. - - By default, the URL will represent a collection of entities, e.g.:: - - /entities - - If kwargs contains an `entity_id`, then the URL will represent a - specific member, e.g.:: - - /entities/{entity_id} - - If a `base_url` is provided, the generated URL will be appended to it. - - If a 'tail' is provided, it will be appended to the end of the URL. - - """ - if dict_args_in_out is None: - dict_args_in_out = {} - - url = dict_args_in_out.pop('base_url', None) or self.base_url or '' - url += '/%s' % self.collection_key - - # do we have a specific entity? - entity_id = dict_args_in_out.pop('%s_id' % self.key, None) - if entity_id is not None: - url += '/%s' % entity_id - - if dict_args_in_out.get('tail'): - url += dict_args_in_out['tail'] - - return url - - @filter_kwargs - def create(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - return self._post( - url, - {self.key: kwargs}, - self.key) - - @filter_kwargs - def get(self, **kwargs): - return self._get( - self.build_url(dict_args_in_out=kwargs), - self.key) - - @filter_kwargs - def head(self, **kwargs): - return self._head(self.build_url(dict_args_in_out=kwargs)) - - def _build_query(self, params): - if params is None: - return '' - else: - return '?%s' % urllib.parse.urlencode(params, doseq=True) - - def build_key_only_query(self, params_list): - """Build a query that does not include values, just keys. - - The Identity API has some calls that define queries without values, - this can not be accomplished by using urllib.parse.urlencode(). This - method builds a query using only the keys. - """ - return '?%s' % '&'.join(params_list) if params_list else '' - - @filter_kwargs - def list(self, fallback_to_auth=False, **kwargs): - if 'id' in kwargs.keys(): - # Ensure that users are not trying to call things like - # ``domains.list(id='default')`` when they should have used - # ``[domains.get(domain_id='default')]`` instead. Keystone supports - # ``GET /v3/domains/{domain_id}``, not ``GET - # /v3/domains?id={domain_id}``. - raise TypeError( - _("list() got an unexpected keyword argument 'id'. To " - "retrieve a single object using a globally unique " - "identifier, try using get() instead.")) - - url = self.build_url(dict_args_in_out=kwargs) - - try: - query = self._build_query(kwargs) - url_query = '%(url)s%(query)s' % {'url': url, 'query': query} - return self._list( - url_query, - self.collection_key) - except ksa_exceptions.EmptyCatalog: - if fallback_to_auth: - return self._list( - url_query, - self.collection_key, - endpoint_filter={'interface': plugin.AUTH_INTERFACE}) - else: - raise - - @filter_kwargs - def put(self, **kwargs): - return self._update( - self.build_url(dict_args_in_out=kwargs), - method='PUT') - - @filter_kwargs - def update(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - - return self._update( - url, - {self.key: kwargs}, - self.key, - method='PATCH') - - @filter_kwargs - def delete(self, **kwargs): - return self._delete( - self.build_url(dict_args_in_out=kwargs)) - - @filter_kwargs - def find(self, **kwargs): - """Find a single item with attributes matching ``**kwargs``.""" - url = self.build_url(dict_args_in_out=kwargs) - - query = self._build_query(kwargs) - url_query = '%(url)s%(query)s' % { - 'url': url, - 'query': query - } - elements = self._list( - url_query, - self.collection_key) - - if not elements: - msg = _("No %(name)s matching %(kwargs)s.") % { - 'name': self.resource_class.__name__, 'kwargs': kwargs} - raise ksa_exceptions.NotFound(404, msg) - elif len(elements) > 1: - raise ksc_exceptions.NoUniqueMatch - else: - return elements[0] - - -class Resource(object): - """Base class for OpenStack resources (tenant, user, etc.). - - This is pretty much just a bag for attributes. - """ - - HUMAN_ID = False - NAME_ATTR = 'name' - - def __init__(self, manager, info, loaded=False): - """Populate and bind to a manager. - - :param manager: BaseManager object - :param info: dictionary representing resource attributes - :param loaded: prevent lazy-loading if set to True - """ - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def __repr__(self): - """Return string representation of resource attributes.""" - reprkeys = sorted(k - for k in self.__dict__.keys() - if k[0] != '_' and k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - @property - def human_id(self): - """Human-readable ID which can be used for bash completion.""" - if self.HUMAN_ID: - name = getattr(self, self.NAME_ATTR, None) - if name is not None: - return strutils.to_slug(name) - return None - - def _add_details(self, info): - for (k, v) in info.items(): - try: - try: - setattr(self, k, v) - except UnicodeEncodeError: - # This happens when we're running with Python version that - # does not support Unicode identifiers (e.g. Python 2.7). - # In that case we can't help but not set this attrubute; - # it'll be available in a dict representation though - pass - self._info[k] = v - except AttributeError: # nosec(cjschaef): we already defined the - # attribute on the class - pass - - def __getattr__(self, k): - """Checking attrbiute existence.""" - if k not in self.__dict__: - # NOTE(bcwaldon): disallow lazy-loading if already loaded once - if not self.is_loaded(): - self.get() - return self.__getattr__(k) - - raise AttributeError(k) - else: - return self.__dict__[k] - - def get(self): - """Support for lazy loading details. - - Some clients, such as novaclient have the option to lazy load the - details, details which can be loaded with this function. - """ - # set_loaded() first ... so if we have to bail, we know we tried. - self.set_loaded(True) - if not hasattr(self.manager, 'get'): - return - - new = self.manager.get(self.id) - if new: - self._add_details(new._info) - - def __eq__(self, other): - """Define equality for resources.""" - if not isinstance(other, Resource): - return NotImplemented - # two resources of different types are not equal - if not isinstance(other, self.__class__): - return False - return self._info == other._info - - def __ne__(self, other): - """Define inequality for resources.""" - return not self == other - - def is_loaded(self): - return self._loaded - - def set_loaded(self, val): - self._loaded = val - - def to_dict(self): - return copy.deepcopy(self._info) - - def delete(self): - return self.manager.delete(self) diff --git a/keystoneclient/baseclient.py b/keystoneclient/baseclient.py deleted file mode 100644 index ca39f6d1..00000000 --- a/keystoneclient/baseclient.py +++ /dev/null @@ -1,46 +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. - -import warnings - - -class Client(object): - - def __init__(self, session): - warnings.warn( - 'keystoneclient.baseclient.Client is deprecated as of the 2.1.0 ' - 'release. It will be removed in future releases.', - DeprecationWarning) - - self.session = session - - def request(self, url, method, **kwargs): - kwargs.setdefault('authenticated', True) - return self.session.request(url, method, **kwargs) - - def get(self, url, **kwargs): - return self.request(url, 'GET', **kwargs) - - def head(self, url, **kwargs): - return self.request(url, 'HEAD', **kwargs) - - def post(self, url, **kwargs): - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - return self.request(url, 'PUT', **kwargs) - - def patch(self, url, **kwargs): - return self.request(url, 'PATCH', **kwargs) - - def delete(self, url, **kwargs): - return self.request(url, 'DELETE', **kwargs) diff --git a/keystoneclient/client.py b/keystoneclient/client.py deleted file mode 100644 index 5da9794d..00000000 --- a/keystoneclient/client.py +++ /dev/null @@ -1,63 +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 debtcollector import removals - -from keystoneclient import discover -from keystoneclient import httpclient -from keystoneclient import session as client_session - - -@removals.remove(message='Use keystoneclient.httpclient.HTTPClient instead', - version='1.7.0', removal_version='2.0.0') -class HTTPClient(httpclient.HTTPClient): - """Deprecated alias for httpclient.HTTPClient. - - This class is deprecated as of the 1.7.0 release in favor of - :class:`keystoneclient.httpclient.HTTPClient` and may be removed in the - 2.0.0 release. - - """ - - -def Client(version=None, unstable=False, session=None, **kwargs): - """Factory function to create a new identity service client. - - The returned client will be either a V3 or V2 client. Check the version - using the :py:attr:`~keystoneclient.v3.client.Client.version` property or - the instance's class (with instanceof). - - :param tuple version: The required version of the identity API. If - specified the client will be selected such that the - major version is equivalent and an endpoint provides - at least the specified minor version. For example to - specify the 3.1 API use ``(3, 1)``. (optional) - :param bool unstable: Accept endpoints not marked as 'stable'. (optional) - :param session: A session object to be used for communication. If one is - not provided it will be constructed from the provided - kwargs. (optional) - :type session: keystoneclient.session.Session - :param kwargs: Additional arguments are passed through to the client - that is being created. - :returns: New keystone client object. - :rtype: :py:class:`keystoneclient.v3.client.Client` or - :py:class:`keystoneclient.v2_0.client.Client` - :raises keystoneclient.exceptions.DiscoveryFailure: if the server's - response is invalid. - :raises keystoneclient.exceptions.VersionNotAvailable: if a suitable client - cannot be found. - """ - if not session: - session = client_session.Session._construct(kwargs) - - d = discover.Discover(session=session, **kwargs) - return d.create_client(version=version, unstable=unstable) diff --git a/keystoneclient/common/__init__.py b/keystoneclient/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py deleted file mode 100644 index 9c3e0bdf..00000000 --- a/keystoneclient/common/cms.py +++ /dev/null @@ -1,444 +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. - -"""Certificate signing functions. - -Call set_subprocess() with the subprocess module. Either Python's -subprocess or eventlet.green.subprocess can be used. - -If set_subprocess() is not called, this module will pick Python's subprocess -or eventlet.green.subprocess based on if os module is patched by eventlet. -""" - -import base64 -import errno -import hashlib -import logging -import zlib - -from debtcollector import removals -import six - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -subprocess = None -LOG = logging.getLogger(__name__) -PKI_ASN1_PREFIX = 'MII' -PKIZ_PREFIX = 'PKIZ_' -PKIZ_CMS_FORM = 'DER' -PKI_ASN1_FORM = 'PEM' -DEFAULT_TOKEN_DIGEST_ALGORITHM = 'sha256' - - -# The openssl cms command exits with these status codes. -# See https://www.openssl.org/docs/man1.1.0/apps/cms.html#EXIT-CODES -class OpensslCmsExitStatus(object): - SUCCESS = 0 - COMMAND_OPTIONS_PARSING_ERROR = 1 - INPUT_FILE_READ_ERROR = 2 - CREATE_CMS_READ_MIME_ERROR = 3 - - -def _ensure_subprocess(): - # NOTE(vish): late loading subprocess so we can - # use the green version if we are in - # eventlet. - global subprocess - if not subprocess: - try: - from eventlet import patcher - if patcher.already_patched: - from eventlet.green import subprocess - else: - import subprocess # nosec(cjschaef): we must be careful when - # using subprocess.Popen with possibly untrusted data, - # assumption is that the certificate/key files provided are - # trustworthy - except ImportError: - import subprocess # noqa # nosec(cjschaef): we must be careful - # when using subprocess.Popen with possibly untrusted data, - # assumption is that the certificate/key files provided are - # trustworthy - - -def set_subprocess(_subprocess=None): - """Set subprocess module to use. - - The subprocess could be eventlet.green.subprocess if using eventlet, - or Python's subprocess otherwise. - """ - global subprocess - subprocess = _subprocess - - -def _check_files_accessible(files): - err = None - retcode = -1 - try: - for try_file in files: - with open(try_file, 'r'): - pass - except IOError as e: - # Catching IOError means there is an issue with - # the given file. - err = try_file, e.strerror - # Emulate openssl behavior, which returns with code 2 when - # access to a file failed. - retcode = OpensslCmsExitStatus.INPUT_FILE_READ_ERROR - - return retcode, err - - -def _process_communicate_handle_oserror(process, data, files): - """Wrapper around process.communicate that checks for OSError.""" - try: - output, err = process.communicate(data) - except OSError as e: - if e.errno != errno.EPIPE: - raise - # OSError with EPIPE only occurs with old Python 2.7.x versions - # http://bugs.python.org/issue10963 - - # The quick exit is typically caused by the openssl command not being - # able to read an input file, so check ourselves if can't read a file. - retcode, err = _check_files_accessible(files) - if process.stderr: - msg = process.stderr.read() - if isinstance(msg, six.binary_type): - msg = msg.decode('utf-8') - if err: - err = (_('Hit OSError in ' - '_process_communicate_handle_oserror(): ' - '%(stderr)s\nLikely due to %(file)s: %(error)s') % - {'stderr': msg, - 'file': err[0], - 'error': err[1]}) - else: - err = (_('Hit OSError in ' - '_process_communicate_handle_oserror(): %s') % msg) - - output = '' - else: - retcode = process.poll() - if err is not None: - if isinstance(err, six.binary_type): - err = err.decode('utf-8') - - return output, err, retcode - - -def _encoding_for_form(inform): - if inform == PKI_ASN1_FORM: - encoding = 'UTF-8' - elif inform == PKIZ_CMS_FORM: - encoding = 'hex' - else: - raise ValueError( - _('"inform" must be one of: %s') % ','.join((PKI_ASN1_FORM, - PKIZ_CMS_FORM))) - - return encoding - - -def cms_verify(formatted, signing_cert_file_name, ca_file_name, - inform=PKI_ASN1_FORM): - """Verify the signature of the contents IAW CMS syntax. - - :raises subprocess.CalledProcessError: - :raises keystoneclient.exceptions.CertificateConfigError: if certificate - is not configured - properly. - """ - _ensure_subprocess() - if isinstance(formatted, six.string_types): - data = bytearray(formatted, _encoding_for_form(inform)) - else: - data = formatted - process = subprocess.Popen(['openssl', 'cms', '-verify', - '-certfile', signing_cert_file_name, - '-CAfile', ca_file_name, - '-inform', 'PEM', - '-nosmimecap', '-nodetach', - '-nocerts', '-noattr'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) - output, err, retcode = _process_communicate_handle_oserror( - process, data, (signing_cert_file_name, ca_file_name)) - - # Do not log errors, as some happen in the positive thread - # instead, catch them in the calling code and log them there. - - # When invoke the openssl >= 1.1.0 with not exist file, return code should - # be 2 instead of 1 and error msg will be returned. - # You can get more from - # https://www.openssl.org/docs/man1.1.0/apps/cms.html#EXIT-CODES - # - # $ openssl cms -verify -certfile not_exist_file -CAfile - # not_exist_file -inform PEM -nosmimecap -nodetach - # -nocerts -noattr - # openssl < 1.1.0 returns - # Error opening certificate file not_exist_file - # openssl >= 1.1.0 returns - # cms: Cannot open input file not_exist_file, No such file or directory - # - if retcode == OpensslCmsExitStatus.INPUT_FILE_READ_ERROR: - if err.startswith('Error reading S/MIME message'): - raise exceptions.CMSError(err) - else: - raise exceptions.CertificateConfigError(err) - # workaround for OpenSSL >= 1.1.0, - # should return OpensslCmsExitStatus.INPUT_FILE_READ_ERROR - elif retcode == OpensslCmsExitStatus.COMMAND_OPTIONS_PARSING_ERROR: - if err.startswith('cms: Cannot open input file'): - raise exceptions.CertificateConfigError(err) - else: - raise subprocess.CalledProcessError(retcode, 'openssl', output=err) - elif retcode != OpensslCmsExitStatus.SUCCESS: - raise subprocess.CalledProcessError(retcode, 'openssl', output=err) - return output - - -def is_pkiz(token_text): - """Determine if a token is PKIZ. - - Checks if the string has the prefix that indicates it is a - Crypto Message Syntax, Z compressed token. - """ - return token_text.startswith(PKIZ_PREFIX) - - -def pkiz_sign(text, - signing_cert_file_name, - signing_key_file_name, - compression_level=6, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - signed = cms_sign_data(text, - signing_cert_file_name, - signing_key_file_name, - PKIZ_CMS_FORM, - message_digest=message_digest) - - compressed = zlib.compress(signed, compression_level) - encoded = PKIZ_PREFIX + base64.urlsafe_b64encode( - compressed).decode('utf-8') - return encoded - - -def pkiz_uncompress(signed_text): - text = signed_text[len(PKIZ_PREFIX):].encode('utf-8') - unencoded = base64.urlsafe_b64decode(text) - uncompressed = zlib.decompress(unencoded) - return uncompressed - - -def pkiz_verify(signed_text, signing_cert_file_name, ca_file_name): - uncompressed = pkiz_uncompress(signed_text) - return cms_verify(uncompressed, signing_cert_file_name, ca_file_name, - inform=PKIZ_CMS_FORM) - - -def token_to_cms(signed_text): - """Convert a custom formatted token to a PEM-formatted token. - - See documentation for cms_to_token() for details on the custom formatting. - """ - copy_of_text = signed_text.replace('-', '/') - - lines = ['-----BEGIN CMS-----'] - lines += [copy_of_text[n:n + 64] for n in range(0, len(copy_of_text), 64)] - lines.append('-----END CMS-----\n') - return '\n'.join(lines) - - -def verify_token(token, signing_cert_file_name, ca_file_name): - return cms_verify(token_to_cms(token), - signing_cert_file_name, - ca_file_name) - - -def is_asn1_token(token): - """Determine if a token appears to be PKI-based. - - thx to ayoung for sorting this out. - - base64 decoded hex representation of MII is 3082:: - - In [3]: binascii.hexlify(base64.b64decode('MII=')) - Out[3]: '3082' - - re: http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf - - :: - - pg4: For tags from 0 to 30 the first octet is the identfier - pg10: Hex 30 means sequence, followed by the length of that sequence. - pg5: Second octet is the length octet - first bit indicates short or long form, next 7 bits encode the - number of subsequent octets that make up the content length octets - as an unsigned binary int - - 82 = 10000010 (first bit indicates long form) - 0000010 = 2 octets of content length - so read the next 2 octets to get the length of the content. - - In the case of a very large content length there could be a requirement to - have more than 2 octets to designate the content length, therefore - requiring us to check for MIM, MIQ, etc. - - :: - - In [4]: base64.b64encode(binascii.a2b_hex('3083')) - Out[4]: 'MIM=' - In [5]: base64.b64encode(binascii.a2b_hex('3084')) - Out[5]: 'MIQ=' - Checking for MI would become invalid at 16 octets of content length - 10010000 = 90 - In [6]: base64.b64encode(binascii.a2b_hex('3090')) - Out[6]: 'MJA=' - Checking for just M is insufficient - - But we will only check for MII: - Max length of the content using 2 octets is 3FFF or 16383. - - It's not practical to support a token of this length or greater in http - therefore, we will check for MII only and ignore the case of larger tokens - """ - return token[:3] == PKI_ASN1_PREFIX - - -@removals.remove(message='Use is_asn1_token() instead.', version='1.7.0', - removal_version='2.0.0') -def is_ans1_token(token): - """Deprecated. - - This function is deprecated as of the 1.7.0 release in favor of - :func:`is_asn1_token` and may be removed in the 2.0.0 release. - """ - return is_asn1_token(token) - - -def cms_sign_text(data_to_sign, signing_cert_file_name, signing_key_file_name, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - return cms_sign_data(data_to_sign, signing_cert_file_name, - signing_key_file_name, message_digest=message_digest) - - -def cms_sign_data(data_to_sign, signing_cert_file_name, signing_key_file_name, - outform=PKI_ASN1_FORM, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - """Use OpenSSL to sign a document. - - Produces a Base64 encoding of a DER formatted CMS Document - http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax - - :param data_to_sign: data to sign - :param signing_cert_file_name: path to the X509 certificate containing - the public key associated with the private key used to sign the data - :param signing_key_file_name: path to the private key used to sign - the data - :param outform: Format for the signed document PKIZ_CMS_FORM or - PKI_ASN1_FORM - :param message_digest: Digest algorithm to use when signing or resigning - - """ - _ensure_subprocess() - if isinstance(data_to_sign, six.string_types): - data = bytearray(data_to_sign, encoding='utf-8') - else: - data = data_to_sign - process = subprocess.Popen(['openssl', 'cms', '-sign', - '-signer', signing_cert_file_name, - '-inkey', signing_key_file_name, - '-outform', 'PEM', - '-nosmimecap', '-nodetach', - '-nocerts', '-noattr', - '-md', message_digest, ], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) - - output, err, retcode = _process_communicate_handle_oserror( - process, data, (signing_cert_file_name, signing_key_file_name)) - - if retcode != OpensslCmsExitStatus.SUCCESS or ('Error' in err): - if retcode == OpensslCmsExitStatus.CREATE_CMS_READ_MIME_ERROR: - LOG.error('Signing error: Unable to load certificate - ' - 'ensure you have configured PKI with ' - '"keystone-manage pki_setup"') - else: - LOG.error('Signing error: %s', err) - raise subprocess.CalledProcessError(retcode, 'openssl') - if outform == PKI_ASN1_FORM: - return output.decode('utf-8') - else: - return output - - -def cms_sign_token(text, signing_cert_file_name, signing_key_file_name, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - output = cms_sign_data(text, signing_cert_file_name, signing_key_file_name, - message_digest=message_digest) - return cms_to_token(output) - - -def cms_to_token(cms_text): - """Convert a CMS-signed token in PEM format to a custom URL-safe format. - - The conversion consists of replacing '/' char in the PEM-formatted token - with the '-' char and doing other such textual replacements to make the - result marshallable via HTTP. The return value can thus be used as the - value of a HTTP header such as "X-Auth-Token". - - This ad-hoc conversion is an unfortunate oversight since the returned - value now does not conform to any of the standard variants of base64 - encoding. It would have been better to use base64url encoding (either on - the PEM formatted text or, perhaps even better, on the inner CMS-signed - binary value without any PEM formatting). In any case, the same conversion - is done in reverse in the other direction (for token verification), so - there are no correctness issues here. Note that the non-standard encoding - of the token will be preserved so as to not break backward compatibility. - - The conversion issue is detailed by the code author in a blog post at - http://adam.younglogic.com/2014/02/compressed-tokens/. - """ - start_delim = '-----BEGIN CMS-----' - end_delim = '-----END CMS-----' - signed_text = cms_text - signed_text = signed_text.replace('/', '-') - signed_text = signed_text.replace(start_delim, '') - signed_text = signed_text.replace(end_delim, '') - signed_text = signed_text.replace('\n', '') - - return signed_text - - -def cms_hash_token(token_id, mode='md5'): - """Hash PKI tokens. - - return: for asn1 or pkiz tokens, returns the hash of the passed in token - otherwise, returns what it was passed in. - """ - if token_id is None: - return None - if is_asn1_token(token_id) or is_pkiz(token_id): - hasher = hashlib.new(mode) - if isinstance(token_id, six.text_type): - token_id = token_id.encode('utf-8') - hasher.update(token_id) - return hasher.hexdigest() - else: - return token_id diff --git a/keystoneclient/contrib/__init__.py b/keystoneclient/contrib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/auth/__init__.py b/keystoneclient/contrib/auth/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/auth/v3/__init__.py b/keystoneclient/contrib/auth/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/auth/v3/oidc.py b/keystoneclient/contrib/auth/v3/oidc.py deleted file mode 100644 index 957c50e4..00000000 --- a/keystoneclient/contrib/auth/v3/oidc.py +++ /dev/null @@ -1,211 +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 oslo_config import cfg -from positional import positional - -from keystoneclient import access -from keystoneclient.auth.identity.v3 import federated - - -class OidcPassword(federated.FederatedBaseAuth): - """Implement authentication plugin for OpenID Connect protocol. - - OIDC or OpenID Connect is a protocol for federated authentication. - - The OpenID Connect specification can be found at:: - ``http://openid.net/specs/openid-connect-core-1_0.html`` - """ - - @classmethod - def get_options(cls): - options = super(OidcPassword, cls).get_options() - options.extend([ - cfg.StrOpt('username', help='Username'), - cfg.StrOpt('password', secret=True, help='Password'), - cfg.StrOpt('client-id', help='OAuth 2.0 Client ID'), - cfg.StrOpt('client-secret', secret=True, - help='OAuth 2.0 Client Secret'), - cfg.StrOpt('access-token-endpoint', - help='OpenID Connect Provider Token Endpoint'), - cfg.StrOpt('scope', default="profile", - help='OpenID Connect scope that is requested from OP') - ]) - return options - - @positional(4) - def __init__(self, auth_url, identity_provider, protocol, - username, password, client_id, client_secret, - access_token_endpoint, scope='profile', - grant_type='password'): - """The OpenID Connect plugin. - - It expects the following: - - :param auth_url: URL of the Identity Service - :type auth_url: string - - :param identity_provider: Name of the Identity Provider the client - will authenticate against - :type identity_provider: string - - :param protocol: Protocol name as configured in keystone - :type protocol: string - - :param username: Username used to authenticate - :type username: string - - :param password: Password used to authenticate - :type password: string - - :param client_id: OAuth 2.0 Client ID - :type client_id: string - - :param client_secret: OAuth 2.0 Client Secret - :type client_secret: string - - :param access_token_endpoint: OpenID Connect Provider Token Endpoint, - for example: - https://localhost:8020/oidc/OP/token - :type access_token_endpoint: string - - :param scope: OpenID Connect scope that is requested from OP, - defaults to "profile", for example: "profile email" - :type scope: string - - :param grant_type: OpenID Connect grant type, it represents the flow - that is used to talk to the OP. Valid values are: - "authorization_code", "refresh_token", or - "password". - :type grant_type: string - """ - super(OidcPassword, self).__init__(auth_url, identity_provider, - protocol) - self._username = username - self._password = password - self.client_id = client_id - self.client_secret = client_secret - self.access_token_endpoint = access_token_endpoint - self.scope = scope - self.grant_type = grant_type - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - def get_unscoped_auth_ref(self, session): - """Authenticate with OpenID Connect and get back claims. - - This is a multi-step process. First an access token must be retrieved, - to do this, the username and password, the OpenID Connect client ID - and secret, and the access token endpoint must be known. - - Secondly, we then exchange the access token upon accessing the - protected Keystone endpoint (federated auth URL). This will trigger - the OpenID Connect Provider to perform a user introspection and - retrieve information (specified in the scope) about the user in - the form of an OpenID Connect Claim. These claims will be sent - to Keystone in the form of environment variables. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: a token data representation - :rtype: :py:class:`keystoneclient.access.AccessInfo` - """ - # get an access token - client_auth = (self.client_id, self.client_secret) - payload = {'grant_type': self.grant_type, 'username': self.username, - 'password': self.password, 'scope': self.scope} - response = self._get_access_token(session, client_auth, payload, - self.access_token_endpoint) - access_token = response.json()['access_token'] - - # use access token against protected URL - headers = {'Authorization': 'Bearer ' + access_token} - response = self._get_keystone_token(session, headers, - self.federated_token_url) - - # grab the unscoped token - token = response.headers['X-Subject-Token'] - token_json = response.json()['token'] - return access.AccessInfoV3(token, **token_json) - - def _get_access_token(self, session, client_auth, payload, - access_token_endpoint): - """Exchange a variety of user supplied values for an access token. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :param client_auth: a tuple representing client id and secret - :type client_auth: tuple - - :param payload: a dict containing various OpenID Connect values, for - example:: - {'grant_type': 'password', 'username': self.username, - 'password': self.password, 'scope': self.scope} - :type payload: dict - - :param access_token_endpoint: URL to use to get an access token, for - example: https://localhost/oidc/token - :type access_token_endpoint: string - """ - op_response = session.post(self.access_token_endpoint, - requests_auth=client_auth, - data=payload, - authenticated=False) - return op_response - - def _get_keystone_token(self, session, headers, federated_token_url): - r"""Exchange an acess token for a keystone token. - - By Sending the access token in an `Authorization: Bearer` header, to - an OpenID Connect protected endpoint (Federated Token URL). The - OpenID Connect server will use the access token to look up information - about the authenticated user (this technique is called instrospection). - The output of the instrospection will be an OpenID Connect Claim, that - will be used against the mapping engine. Should the mapping engine - succeed, a Keystone token will be presented to the user. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :param headers: an Authorization header containing the access token. - :type headers_: dict - - :param federated_auth_url: Protected URL for federated authentication, - for example: https://localhost:5000/v3/\ - OS-FEDERATION/identity_providers/bluepages/\ - protocols/oidc/auth - :type federated_auth_url: string - """ - auth_response = session.post(self.federated_token_url, - headers=headers, - authenticated=False) - return auth_response diff --git a/keystoneclient/contrib/auth/v3/saml2.py b/keystoneclient/contrib/auth/v3/saml2.py deleted file mode 100644 index 8a07b7f3..00000000 --- a/keystoneclient/contrib/auth/v3/saml2.py +++ /dev/null @@ -1,920 +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. - -import datetime -import uuid - -from lxml import etree # nosec(cjschaef): used to create xml, not parse it -from oslo_config import cfg -from six.moves import urllib - -from keystoneclient import access -from keystoneclient.auth.identity import v3 -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class _BaseSAMLPlugin(v3.AuthConstructor): - - HTTP_MOVED_TEMPORARILY = 302 - HTTP_SEE_OTHER = 303 - - PROTOCOL = 'saml2' - - @staticmethod - def _first(_list): - if len(_list) != 1: - raise IndexError(_("Only single element list is acceptable")) - return _list[0] - - @staticmethod - def str_to_xml(content, msg=None, include_exc=True): - try: - return etree.XML(content) - except etree.XMLSyntaxError as e: - if not msg: - msg = str(e) - else: - msg = msg % e if include_exc else msg - raise exceptions.AuthorizationFailure(msg) - - @staticmethod - def xml_to_str(content, **kwargs): - return etree.tostring(content, **kwargs) - - @property - def token_url(self): - """Return full URL where authorization data is sent.""" - values = { - 'host': self.auth_url.rstrip('/'), - 'identity_provider': self.identity_provider, - 'protocol': self.PROTOCOL - } - url = ("%(host)s/OS-FEDERATION/identity_providers/" - "%(identity_provider)s/protocols/%(protocol)s/auth") - url = url % values - - return url - - @classmethod - def get_options(cls): - options = super(_BaseSAMLPlugin, cls).get_options() - options.extend([ - cfg.StrOpt('identity-provider', help="Identity Provider's name"), - cfg.StrOpt('identity-provider-url', - help="Identity Provider's URL"), - cfg.StrOpt('username', dest='username', help='Username', - deprecated_name='user-name'), - cfg.StrOpt('password', secret=True, help='Password') - ]) - return options - - -class Saml2UnscopedTokenAuthMethod(v3.AuthMethod): - _method_parameters = [] - - def get_auth_data(self, session, auth, headers, **kwargs): - raise exceptions.MethodNotImplemented(_('This method should never ' - 'be called')) - - -class Saml2UnscopedToken(_BaseSAMLPlugin): - r"""Implement authentication plugin for SAML2 protocol. - - ECP stands for `Enhanced Client or Proxy` and is a SAML2 extension - for federated authentication where a transportation layer consists of - HTTP protocol and XML SOAP messages. - - `Read for more information - `_ on ECP. - - Reference the `SAML2 ECP specification `_. - - Currently only HTTPBasicAuth mechanism is available for the IdP - authenication. - - :param auth_url: URL of the Identity Service - :type auth_url: string - - :param identity_provider: name of the Identity Provider the client will - authenticate against. This parameter will be used - to build a dynamic URL used to obtain unscoped - OpenStack token. - :type identity_provider: string - - :param identity_provider_url: An Identity Provider URL, where the SAML2 - authn request will be sent. - :type identity_provider_url: string - - :param username: User's login - :type username: string - - :param password: User's password - :type password: string - - """ - - _auth_method_class = Saml2UnscopedTokenAuthMethod - - SAML2_HEADER_INDEX = 0 - ECP_SP_EMPTY_REQUEST_HEADERS = { - 'Accept': 'text/html, application/vnd.paos+xml', - 'PAOS': ('ver="urn:liberty:paos:2003-08";"urn:oasis:names:tc:' - 'SAML:2.0:profiles:SSO:ecp"') - } - - ECP_SP_SAML2_REQUEST_HEADERS = { - 'Content-Type': 'application/vnd.paos+xml' - } - - ECP_SAML2_NAMESPACES = { - 'ecp': 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp', - 'S': 'http://schemas.xmlsoap.org/soap/envelope/', - 'paos': 'urn:liberty:paos:2003-08' - } - - ECP_RELAY_STATE = '//ecp:RelayState' - - ECP_SERVICE_PROVIDER_CONSUMER_URL = ('/S:Envelope/S:Header/paos:Request/' - '@responseConsumerURL') - - ECP_IDP_CONSUMER_URL = ('/S:Envelope/S:Header/ecp:Response/' - '@AssertionConsumerServiceURL') - - SOAP_FAULT = """ - - - - S:Server - responseConsumerURL from SP and - assertionConsumerServiceURL from IdP do not match - - - - - """ - - def __init__(self, auth_url, - identity_provider, - identity_provider_url, - username, password, - **kwargs): - super(Saml2UnscopedToken, self).__init__(auth_url=auth_url, **kwargs) - self.identity_provider = identity_provider - self.identity_provider_url = identity_provider_url - self._username, self._password = username, password - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - def _handle_http_ecp_redirect(self, session, response, method, **kwargs): - if response.status_code not in (self.HTTP_MOVED_TEMPORARILY, - self.HTTP_SEE_OTHER): - return response - - location = response.headers['location'] - return session.request(location, method, authenticated=False, - **kwargs) - - def _prepare_idp_saml2_request(self, saml2_authn_request): - header = saml2_authn_request[self.SAML2_HEADER_INDEX] - saml2_authn_request.remove(header) - - def _check_consumer_urls(self, session, sp_response_consumer_url, - idp_sp_response_consumer_url): - """Check if consumer URLs issued by SP and IdP are equal. - - In the initial SAML2 authn Request issued by a Service Provider - there is a url called ``consumer url``. A trusted Identity Provider - should issue identical url. If the URLs are not equal the federated - authn process should be interrupted and the user should be warned. - - :param session: session object to send out HTTP requests. - :type session: keystoneclient.session.Session - :param sp_response_consumer_url: consumer URL issued by a SP - :type sp_response_consumer_url: string - :param idp_sp_response_consumer_url: consumer URL issued by an IdP - :type idp_sp_response_consumer_url: string - - """ - if sp_response_consumer_url != idp_sp_response_consumer_url: - # send fault message to the SP, discard the response - session.post(sp_response_consumer_url, data=self.SOAP_FAULT, - headers=self.ECP_SP_SAML2_REQUEST_HEADERS, - authenticated=False) - - # prepare error message and raise an exception. - msg = _("Consumer URLs from Service Provider %(service_provider)s " - "%(sp_consumer_url)s and Identity Provider " - "%(identity_provider)s %(idp_consumer_url)s are not equal") - msg = msg % { - 'service_provider': self.token_url, - 'sp_consumer_url': sp_response_consumer_url, - 'identity_provider': self.identity_provider, - 'idp_consumer_url': idp_sp_response_consumer_url - } - - raise exceptions.ValidationError(msg) - - def _send_service_provider_request(self, session): - """Initial HTTP GET request to the SAML2 protected endpoint. - - It's crucial to include HTTP headers indicating that the client is - willing to take advantage of the ECP SAML2 extension and receive data - as the SOAP. - Unlike standard authentication methods in the OpenStack Identity, - the client accesses:: - ``/v3/OS-FEDERATION/identity_providers/{identity_providers}/ - protocols/{protocol}/auth`` - - After a successful HTTP call the HTTP response should include SAML2 - authn request in the XML format. - - If a HTTP response contains ``X-Subject-Token`` in the headers and - the response body is a valid JSON assume the user was already - authenticated and Keystone returned a valid unscoped token. - Return True indicating the user was already authenticated. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - """ - sp_response = session.get(self.token_url, - headers=self.ECP_SP_EMPTY_REQUEST_HEADERS, - authenticated=False) - - if 'X-Subject-Token' in sp_response.headers: - self.authenticated_response = sp_response - return True - - try: - self.saml2_authn_request = etree.XML(sp_response.content) - except etree.XMLSyntaxError as e: - msg = _("SAML2: Error parsing XML returned " - "from Service Provider, reason: %s") % e - raise exceptions.AuthorizationFailure(msg) - - relay_state = self.saml2_authn_request.xpath( - self.ECP_RELAY_STATE, namespaces=self.ECP_SAML2_NAMESPACES) - self.relay_state = self._first(relay_state) - - sp_response_consumer_url = self.saml2_authn_request.xpath( - self.ECP_SERVICE_PROVIDER_CONSUMER_URL, - namespaces=self.ECP_SAML2_NAMESPACES) - self.sp_response_consumer_url = self._first(sp_response_consumer_url) - return False - - def _send_idp_saml2_authn_request(self, session): - """Present modified SAML2 authn assertion from the Service Provider.""" - self._prepare_idp_saml2_request(self.saml2_authn_request) - idp_saml2_authn_request = self.saml2_authn_request - - # Currently HTTPBasicAuth method is hardcoded into the plugin - idp_response = session.post( - self.identity_provider_url, - headers={'Content-type': 'text/xml'}, - data=etree.tostring(idp_saml2_authn_request), - requests_auth=(self.username, self.password), - authenticated=False, log=False) - - try: - self.saml2_idp_authn_response = etree.XML(idp_response.content) - except etree.XMLSyntaxError as e: - msg = _("SAML2: Error parsing XML returned " - "from Identity Provider, reason: %s") % e - raise exceptions.AuthorizationFailure(msg) - - idp_response_consumer_url = self.saml2_idp_authn_response.xpath( - self.ECP_IDP_CONSUMER_URL, - namespaces=self.ECP_SAML2_NAMESPACES) - - self.idp_response_consumer_url = self._first(idp_response_consumer_url) - - self._check_consumer_urls(session, self.idp_response_consumer_url, - self.sp_response_consumer_url) - - def _send_service_provider_saml2_authn_response(self, session): - """Present SAML2 assertion to the Service Provider. - - The assertion is issued by a trusted Identity Provider for the - authenticated user. This function directs the HTTP request to SP - managed URL, for instance: ``https://:/Shibboleth.sso/ - SAML2/ECP``. - Upon success the there's a session created and access to the protected - resource is granted. Many implementations of the SP return HTTP 302/303 - status code pointing to the protected URL (``https://:/v3/ - OS-FEDERATION/identity_providers/{identity_provider}/protocols/ - {protocol_id}/auth`` in this case). Saml2 plugin should point to that - URL again, with HTTP GET method, expecting an unscoped token. - - :param session: a session object to send out HTTP requests. - - """ - self.saml2_idp_authn_response[0][0] = self.relay_state - - response = session.post( - self.idp_response_consumer_url, - headers=self.ECP_SP_SAML2_REQUEST_HEADERS, - data=etree.tostring(self.saml2_idp_authn_response), - authenticated=False, redirect=False) - - # Don't follow HTTP specs - after the HTTP 302/303 response don't - # repeat the call directed to the Location URL. In this case, this is - # an indication that saml2 session is now active and protected resource - # can be accessed. - response = self._handle_http_ecp_redirect( - session, response, method='GET', - headers=self.ECP_SP_SAML2_REQUEST_HEADERS) - - self.authenticated_response = response - - def _get_unscoped_token(self, session): - """Get unscoped OpenStack token after federated authentication. - - This is a multi-step process including multiple HTTP requests. - - The federated authentication consists of:: - * HTTP GET request to the Identity Service (acting as a Service - Provider). Client utilizes URL:: - ``/v3/OS-FEDERATION/identity_providers/{identity_provider}/ - protocols/saml2/auth``. - It's crucial to include HTTP headers indicating we are expecting - SOAP message in return. - Service Provider should respond with such SOAP message. - This step is handed by a method - ``Saml2UnscopedToken_send_service_provider_request()`` - - * HTTP POST request to the external Identity Provider service with - ECP extension enabled. The content sent is a header removed SOAP - message returned from the Service Provider. It's also worth noting - that ECP extension to the SAML2 doesn't define authentication method. - The most popular is HttpBasicAuth with just user and password. - Other possibilities could be X509 certificates or Kerberos. - Upon successful authentication the user should receive a SAML2 - assertion. - This step is handed by a method - ``Saml2UnscopedToken_send_idp_saml2_authn_request(session)`` - - * HTTP POST request again to the Service Provider. The body of the - request includes SAML2 assertion issued by a trusted Identity - Provider. The request should be sent to the Service Provider - consumer url specified in the SAML2 assertion. - Providing the authentication was successful and both Service Provider - and Identity Providers are trusted to each other, the Service - Provider will issue an unscoped token with a list of groups the - federated user is a member of. - This step is handed by a method - ``Saml2UnscopedToken_send_service_provider_saml2_authn_response()`` - - Unscoped token example:: - - { - "token": { - "methods": [ - "saml2" - ], - "user": { - "id": "username%40example.com", - "name": "username@example.com", - "OS-FEDERATION": { - "identity_provider": "ACME", - "protocol": "saml2", - "groups": [ - {"id": "abc123"}, - {"id": "bcd234"} - ] - } - } - } - } - - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: (token, token_json) - - """ - saml_authenticated = self._send_service_provider_request(session) - if not saml_authenticated: - self._send_idp_saml2_authn_request(session) - self._send_service_provider_saml2_authn_response(session) - return (self.authenticated_response.headers['X-Subject-Token'], - self.authenticated_response.json()['token']) - - def get_auth_ref(self, session, **kwargs): - """Authenticate via SAML2 protocol and retrieve unscoped token. - - This is a multi-step process where a client does federated authn - receives an unscoped token. - - Federated authentication utilizing SAML2 Enhanced Client or Proxy - extension. See ``Saml2UnscopedToken_get_unscoped_token()`` - for more information on that step. - Upon successful authentication and assertion mapping an - unscoped token is returned and stored within the plugin object for - further use. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :return: an object with scoped token's id and unscoped token json - included. - :rtype: :py:class:`keystoneclient.access.AccessInfoV3` - - """ - token, token_json = self._get_unscoped_token(session) - return access.AccessInfoV3(token, - **token_json) - - -class ADFSUnscopedToken(_BaseSAMLPlugin): - """Authentication plugin for Microsoft ADFS2.0 IdPs. - - :param auth_url: URL of the Identity Service - :type auth_url: string - - :param identity_provider: name of the Identity Provider the client will - authenticate against. This parameter will be used - to build a dynamic URL used to obtain unscoped - OpenStack token. - :type identity_provider: string - - :param identity_provider_url: An Identity Provider URL, where the SAML2 - authentication request will be sent. - :type identity_provider_url: string - - :param service_provider_endpoint: Endpoint where an assertion is being - sent, for instance: ``https://host.domain/Shibboleth.sso/ADFS`` - :type service_provider_endpoint: string - - :param username: User's login - :type username: string - - :param password: User's password - :type password: string - - """ - - _auth_method_class = Saml2UnscopedTokenAuthMethod - - DEFAULT_ADFS_TOKEN_EXPIRATION = 120 - - HEADER_SOAP = {"Content-Type": "application/soap+xml; charset=utf-8"} - HEADER_X_FORM = {"Content-Type": "application/x-www-form-urlencoded"} - - NAMESPACES = { - 's': 'http://www.w3.org/2003/05/soap-envelope', - 'a': 'http://www.w3.org/2005/08/addressing', - 'u': ('http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd') - } - - ADFS_TOKEN_NAMESPACES = { - 's': 'http://www.w3.org/2003/05/soap-envelope', - 't': 'http://docs.oasis-open.org/ws-sx/ws-trust/200512' - } - ADFS_ASSERTION_XPATH = ('/s:Envelope/s:Body' - '/t:RequestSecurityTokenResponseCollection' - '/t:RequestSecurityTokenResponse') - - def __init__(self, auth_url, identity_provider, identity_provider_url, - service_provider_endpoint, username, password, **kwargs): - super(ADFSUnscopedToken, self).__init__(auth_url=auth_url, **kwargs) - self.identity_provider = identity_provider - self.identity_provider_url = identity_provider_url - self.service_provider_endpoint = service_provider_endpoint - self._username, self._password = username, password - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - @classmethod - def get_options(cls): - options = super(ADFSUnscopedToken, cls).get_options() - - options.extend([ - cfg.StrOpt('service-provider-endpoint', - help="Service Provider's Endpoint") - ]) - return options - - def _cookies(self, session): - """Check if cookie jar is not empty. - - keystoneclient.session.Session object doesn't have a cookies attribute. - We should then try fetching cookies from the underlying - requests.Session object. If that fails too, there is something wrong - and let Python raise the AttributeError. - - :param session - :returns: True if cookie jar is nonempty, False otherwise - :raises AttributeError: in case cookies are not find anywhere - - """ - try: - return bool(session.cookies) - except AttributeError: # nosec(cjschaef): fetch cookies from - # underylying requests.Session object, or fail trying - pass - - return bool(session.session.cookies) - - def _token_dates(self, fmt='%Y-%m-%dT%H:%M:%S.%fZ'): - """Calculate created and expires datetime objects. - - The method is going to be used for building ADFS Request Security - Token message. Time interval between ``created`` and ``expires`` - dates is now static and equals to 120 seconds. ADFS security tokens - should not be live too long, as currently ``keystoneclient`` - doesn't have mechanisms for reusing such tokens (every time ADFS authn - method is called, keystoneclient will login with the ADFS instance). - - :param fmt: Datetime format for specifying string format of a date. - It should not be changed if the method is going to be used - for building the ADFS security token request. - :type fmt: string - - """ - date_created = datetime.datetime.utcnow() - date_expires = date_created + datetime.timedelta( - seconds=self.DEFAULT_ADFS_TOKEN_EXPIRATION) - return [_time.strftime(fmt) for _time in (date_created, date_expires)] - - def _prepare_adfs_request(self): - """Build the ADFS Request Security Token SOAP message. - - Some values like username or password are inserted in the request. - - """ - WSS_SECURITY_NAMESPACE = { - 'o': ('http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-secext-1.0.xsd') - } - - TRUST_NAMESPACE = { - 'trust': 'http://docs.oasis-open.org/ws-sx/ws-trust/200512' - } - - WSP_NAMESPACE = { - 'wsp': 'http://schemas.xmlsoap.org/ws/2004/09/policy' - } - - WSA_NAMESPACE = { - 'wsa': 'http://www.w3.org/2005/08/addressing' - } - - root = etree.Element( - '{http://www.w3.org/2003/05/soap-envelope}Envelope', - nsmap=self.NAMESPACES) - - header = etree.SubElement( - root, '{http://www.w3.org/2003/05/soap-envelope}Header') - action = etree.SubElement( - header, "{http://www.w3.org/2005/08/addressing}Action") - action.set( - "{http://www.w3.org/2003/05/soap-envelope}mustUnderstand", "1") - action.text = ('http://docs.oasis-open.org/ws-sx/ws-trust/200512' - '/RST/Issue') - - messageID = etree.SubElement( - header, '{http://www.w3.org/2005/08/addressing}MessageID') - messageID.text = 'urn:uuid:' + uuid.uuid4().hex - replyID = etree.SubElement( - header, '{http://www.w3.org/2005/08/addressing}ReplyTo') - address = etree.SubElement( - replyID, '{http://www.w3.org/2005/08/addressing}Address') - address.text = 'http://www.w3.org/2005/08/addressing/anonymous' - - to = etree.SubElement( - header, '{http://www.w3.org/2005/08/addressing}To') - to.set("{http://www.w3.org/2003/05/soap-envelope}mustUnderstand", "1") - - security = etree.SubElement( - header, '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-secext-1.0.xsd}Security', - nsmap=WSS_SECURITY_NAMESPACE) - - security.set( - "{http://www.w3.org/2003/05/soap-envelope}mustUnderstand", "1") - - timestamp = etree.SubElement( - security, ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Timestamp')) - timestamp.set( - ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Id'), '_0') - - created = etree.SubElement( - timestamp, ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Created')) - - expires = etree.SubElement( - timestamp, ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Expires')) - - created.text, expires.text = self._token_dates() - - usernametoken = etree.SubElement( - security, '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-secext-1.0.xsd}UsernameToken') - usernametoken.set( - ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-' - 'wssecurity-utility-1.0.xsd}u'), "uuid-%s-1" % uuid.uuid4().hex) - - username = etree.SubElement( - usernametoken, ('{http://docs.oasis-open.org/wss/2004/01/oasis-' - '200401-wss-wssecurity-secext-1.0.xsd}Username')) - password = etree.SubElement( - usernametoken, ('{http://docs.oasis-open.org/wss/2004/01/oasis-' - '200401-wss-wssecurity-secext-1.0.xsd}Password'), - Type=('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-' - 'username-token-profile-1.0#PasswordText')) - - body = etree.SubElement( - root, "{http://www.w3.org/2003/05/soap-envelope}Body") - - request_security_token = etree.SubElement( - body, ('{http://docs.oasis-open.org/ws-sx/ws-trust/200512}' - 'RequestSecurityToken'), nsmap=TRUST_NAMESPACE) - - applies_to = etree.SubElement( - request_security_token, - '{http://schemas.xmlsoap.org/ws/2004/09/policy}AppliesTo', - nsmap=WSP_NAMESPACE) - - endpoint_reference = etree.SubElement( - applies_to, - '{http://www.w3.org/2005/08/addressing}EndpointReference', - nsmap=WSA_NAMESPACE) - - wsa_address = etree.SubElement( - endpoint_reference, - '{http://www.w3.org/2005/08/addressing}Address') - - keytype = etree.SubElement( - request_security_token, - '{http://docs.oasis-open.org/ws-sx/ws-trust/200512}KeyType') - keytype.text = ('http://docs.oasis-open.org/ws-sx/' - 'ws-trust/200512/Bearer') - - request_type = etree.SubElement( - request_security_token, - '{http://docs.oasis-open.org/ws-sx/ws-trust/200512}RequestType') - request_type.text = ('http://docs.oasis-open.org/ws-sx/' - 'ws-trust/200512/Issue') - token_type = etree.SubElement( - request_security_token, - '{http://docs.oasis-open.org/ws-sx/ws-trust/200512}TokenType') - token_type.text = 'urn:oasis:names:tc:SAML:1.0:assertion' - - # After constructing the request, let's plug in some values - username.text = self.username - password.text = self.password - to.text = self.identity_provider_url - wsa_address.text = self.service_provider_endpoint - - self.prepared_request = root - - def _get_adfs_security_token(self, session): - """Send ADFS Security token to the ADFS server. - - Store the result in the instance attribute and raise an exception in - case the response is not valid XML data. - - If a user cannot authenticate due to providing bad credentials, the - ADFS2.0 server will return a HTTP 500 response and a XML Fault message. - If ``exceptions.InternalServerError`` is caught, the method tries to - parse the XML response. - If parsing is unsuccessful, an ``exceptions.AuthorizationFailure`` is - raised with a reason from the XML fault. Otherwise an original - ``exceptions.InternalServerError`` is re-raised. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.AuthorizationFailure: when HTTP - response from the ADFS server is not a valid XML ADFS security - token. - :raises keystoneclient.exceptions.InternalServerError: If response - status code is HTTP 500 and the response XML cannot be - recognized. - - """ - def _get_failure(e): - xpath = '/s:Envelope/s:Body/s:Fault/s:Code/s:Subcode/s:Value' - content = e.response.content - try: - obj = self.str_to_xml(content).xpath( - xpath, namespaces=self.NAMESPACES) - obj = self._first(obj) - return obj.text - # NOTE(marek-denis): etree.Element.xpath() doesn't raise an - # exception, it just returns an empty list. In that case, _first() - # will raise IndexError and we should treat it as an indication XML - # is not valid. exceptions.AuthorizationFailure can be raised from - # str_to_xml(), however since server returned HTTP 500 we should - # re-raise exceptions.InternalServerError. - except (IndexError, exceptions.AuthorizationFailure): - raise e - - request_security_token = self.xml_to_str(self.prepared_request) - try: - response = session.post( - url=self.identity_provider_url, headers=self.HEADER_SOAP, - data=request_security_token, authenticated=False) - except exceptions.InternalServerError as e: - reason = _get_failure(e) - raise exceptions.AuthorizationFailure(reason) - msg = _("Error parsing XML returned from " - "the ADFS Identity Provider, reason: %s") - self.adfs_token = self.str_to_xml(response.content, msg) - - def _prepare_sp_request(self): - """Prepare ADFS Security Token to be sent to the Service Provider. - - The method works as follows: - * Extract SAML2 assertion from the ADFS Security Token. - * Replace namespaces - * urlencode assertion - * concatenate static string with the encoded assertion - - """ - assertion = self.adfs_token.xpath( - self.ADFS_ASSERTION_XPATH, namespaces=self.ADFS_TOKEN_NAMESPACES) - assertion = self._first(assertion) - assertion = self.xml_to_str(assertion) - # TODO(marek-denis): Ideally no string replacement should occur. - # Unfortunately lxml doesn't allow for namespaces changing in-place and - # probably the only solution good for now is to build the assertion - # from scratch and reuse values from the adfs security token. - assertion = assertion.replace( - b'http://docs.oasis-open.org/ws-sx/ws-trust/200512', - b'http://schemas.xmlsoap.org/ws/2005/02/trust') - - encoded_assertion = urllib.parse.quote(assertion) - self.encoded_assertion = 'wa=wsignin1.0&wresult=' + encoded_assertion - - def _send_assertion_to_service_provider(self, session): - """Send prepared assertion to a service provider. - - As the assertion doesn't contain a protected resource, the value from - the ``location`` header is not valid and we should not let the Session - object get redirected there. The aim of this call is to get a cookie in - the response which is required for entering a protected endpoint. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :raises: Corresponding HTTP error exception - - """ - session.post( - url=self.service_provider_endpoint, data=self.encoded_assertion, - headers=self.HEADER_X_FORM, redirect=False, authenticated=False) - - def _access_service_provider(self, session): - """Access protected endpoint and fetch unscoped token. - - After federated authentication workflow a protected endpoint should be - accessible with the session object. The access is granted basing on the - cookies stored within the session object. If, for some reason no - cookies are present (quantity test) it means something went wrong and - user will not be able to fetch an unscoped token. In that case an - ``exceptions.AuthorizationFailure` exception is raised and no HTTP call - is even made. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.AuthorizationFailure: in case session - object has empty cookie jar. - - """ - if self._cookies(session) is False: - raise exceptions.AuthorizationFailure( - _("Session object doesn't contain a cookie, therefore you are " - "not allowed to enter the Identity Provider's protected " - "area.")) - self.authenticated_response = session.get(self.token_url, - authenticated=False) - - def _get_unscoped_token(self, session, *kwargs): - """Retrieve unscoped token after authentcation with ADFS server. - - This is a multistep process:: - - * Prepare ADFS Request Securty Token - - build an etree.XML object filling certain attributes with proper user - credentials, created/expires dates (ticket is be valid for 120 seconds - as currently we don't handle reusing ADFS issued security tokens) . - Step handled by ``ADFSUnscopedToken._prepare_adfs_request()`` method. - - * Send ADFS Security token to the ADFS server. Step handled by - ``ADFSUnscopedToken._get_adfs_security_token()`` method. - - * Receive and parse security token, extract actual SAML assertion and - prepare a request addressed for the Service Provider endpoint. - This also includes changing namespaces in the XML document. Step - handled by ``ADFSUnscopedToken._prepare_sp_request()`` method. - - * Send prepared assertion to the Service Provider endpoint. Usually - the server will respond with HTTP 301 code which should be ignored as - the 'location' header doesn't contain protected area. The goal of this - operation is fetching the session cookie which later allows for - accessing protected URL endpoints. Step handed by - ``ADFSUnscopedToken._send_assertion_to_service_provider()`` method. - - * Once the session cookie is issued, the protected endpoint can be - accessed and an unscoped token can be retrieved. Step handled by - ``ADFSUnscopedToken._access_service_provider()`` method. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: (Unscoped federated token, token JSON body) - - """ - self._prepare_adfs_request() - self._get_adfs_security_token(session) - self._prepare_sp_request() - self._send_assertion_to_service_provider(session) - self._access_service_provider(session) - - try: - return (self.authenticated_response.headers['X-Subject-Token'], - self.authenticated_response.json()['token']) - except (KeyError, ValueError): - raise exceptions.InvalidResponse( - response=self.authenticated_response) - - def get_auth_ref(self, session, **kwargs): - token, token_json = self._get_unscoped_token(session) - return access.AccessInfoV3(token, **token_json) - - -class Saml2ScopedTokenMethod(v3.TokenMethod): - _method_name = 'saml2' - - def get_auth_data(self, session, auth, headers, **kwargs): - """Build and return request body for token scoping step.""" - t = super(Saml2ScopedTokenMethod, self).get_auth_data( - session, auth, headers, **kwargs) - _token_method, token = t - return self._method_name, token - - -class Saml2ScopedToken(v3.Token): - """Class for scoping unscoped saml2 token.""" - - _auth_method_class = Saml2ScopedTokenMethod - - def __init__(self, auth_url, token, **kwargs): - super(Saml2ScopedToken, self).__init__(auth_url, token, **kwargs) - if not (self.project_id or self.domain_id): - raise exceptions.ValidationError( - _('Neither project nor domain specified')) diff --git a/keystoneclient/contrib/ec2/__init__.py b/keystoneclient/contrib/ec2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/ec2/utils.py b/keystoneclient/contrib/ec2/utils.py deleted file mode 100644 index 1ef5df4d..00000000 --- a/keystoneclient/contrib/ec2/utils.py +++ /dev/null @@ -1,287 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2011 - 2012 Justin Santa Barbara -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import base64 -import hashlib -import hmac -import re - -import six -from six.moves import urllib - -from keystoneclient.i18n import _ - - -class Ec2Signer(object): - """Utility class for EC2 signing of request. - - This allows a request to be signed with an AWS style signature, - which can then be used for authentication via the keystone ec2 - authentication extension. - """ - - def __init__(self, secret_key): - self.secret_key = secret_key.encode() - self.hmac = hmac.new(self.secret_key, digestmod=hashlib.sha1) - if hashlib.sha256: - self.hmac_256 = hmac.new(self.secret_key, digestmod=hashlib.sha256) - - def _v4_creds(self, credentials): - """Detect if the credentials are for a v4 signed request. - - Check is needed since AWS removed the SignatureVersion field from - the v4 request spec... - - This expects a dict of the request headers to be passed in the - credentials dict, since the recommended way to pass v4 creds is - via the 'Authorization' header - see http://docs.aws.amazon.com/general/latest/gr/ - sigv4-signed-request-examples.html - - Alternatively X-Amz-Algorithm can be specified as a query parameter, - and the authentication data can also passed as query parameters. - - Note a hash of the request body is also required in the credentials - for v4 auth to work in the body_hash key, calculated via: - hashlib.sha256(req.body).hexdigest() - """ - try: - auth_str = credentials['headers']['Authorization'] - if auth_str.startswith('AWS4-HMAC-SHA256'): - return True - except KeyError: - # Alternatively the Authorization data can be passed via - # the query params list, check X-Amz-Algorithm=AWS4-HMAC-SHA256 - try: - if (credentials['params']['X-Amz-Algorithm'] == - 'AWS4-HMAC-SHA256'): - return True - except KeyError: # nosec(cjschaef): in cases of not finding - # entries, simply return False - pass - - return False - - def generate(self, credentials): - """Generate auth string according to what SignatureVersion is given.""" - signature_version = credentials['params'].get('SignatureVersion') - if signature_version == '0': - return self._calc_signature_0(credentials['params']) - if signature_version == '1': - return self._calc_signature_1(credentials['params']) - if signature_version == '2': - return self._calc_signature_2(credentials['params'], - credentials['verb'], - credentials['host'], - credentials['path']) - if self._v4_creds(credentials): - return self._calc_signature_4(credentials['params'], - credentials['verb'], - credentials['host'], - credentials['path'], - credentials['headers'], - credentials['body_hash']) - - if signature_version is not None: - raise Exception(_('Unknown signature version: %s') % - signature_version) - else: - raise Exception(_('Unexpected signature format')) - - @staticmethod - def _get_utf8_value(value): - """Get the UTF8-encoded version of a value.""" - if not isinstance(value, (six.binary_type, six.text_type)): - value = str(value) - if isinstance(value, six.text_type): - return value.encode('utf-8') - else: - return value - - def _calc_signature_0(self, params): - """Generate AWS signature version 0 string.""" - s = (params['Action'] + params['Timestamp']).encode('utf-8') - self.hmac.update(s) - return base64.b64encode(self.hmac.digest()).decode('utf-8') - - def _calc_signature_1(self, params): - """Generate AWS signature version 1 string.""" - keys = list(params) - keys.sort(key=six.text_type.lower) - for key in keys: - self.hmac.update(key.encode('utf-8')) - val = self._get_utf8_value(params[key]) - self.hmac.update(val) - return base64.b64encode(self.hmac.digest()).decode('utf-8') - - @staticmethod - def _canonical_qs(params): - """Construct a sorted, correctly encoded query string. - - This is required for _calc_signature_2 and _calc_signature_4. - """ - keys = list(params) - keys.sort() - pairs = [] - for key in keys: - val = Ec2Signer._get_utf8_value(params[key]) - val = urllib.parse.quote(val, safe='-_~') - pairs.append(urllib.parse.quote(key, safe='') + '=' + val) - qs = '&'.join(pairs) - return qs - - def _calc_signature_2(self, params, verb, server_string, path): - """Generate AWS signature version 2 string.""" - string_to_sign = '%s\n%s\n%s\n' % (verb, server_string, path) - if self.hmac_256: - current_hmac = self.hmac_256 - params['SignatureMethod'] = 'HmacSHA256' - else: - current_hmac = self.hmac - params['SignatureMethod'] = 'HmacSHA1' - string_to_sign += self._canonical_qs(params) - current_hmac.update(string_to_sign.encode('utf-8')) - b64 = base64.b64encode(current_hmac.digest()).decode('utf-8') - return b64 - - def _calc_signature_4(self, params, verb, server_string, path, headers, - body_hash): - """Generate AWS signature version 4 string.""" - def sign(key, msg): - return hmac.new(key, self._get_utf8_value(msg), - hashlib.sha256).digest() - - def signature_key(datestamp, region_name, service_name): - """Signature key derivation. - - See http://docs.aws.amazon.com/general/latest/gr/ - signature-v4-examples.html#signature-v4-examples-python - """ - k_date = sign(self._get_utf8_value(b"AWS4" + self.secret_key), - datestamp) - k_region = sign(k_date, region_name) - k_service = sign(k_region, service_name) - k_signing = sign(k_service, "aws4_request") - return k_signing - - def auth_param(param_name): - """Get specified auth parameter. - - Provided via one of: - - the Authorization header - - the X-Amz-* query parameters - """ - try: - auth_str = headers['Authorization'] - param_str = auth_str.partition( - '%s=' % param_name)[2].split(',')[0] - except KeyError: - param_str = params.get('X-Amz-%s' % param_name) - return param_str - - def date_param(): - """Get the X-Amz-Date' value. - - The value can be either a header or parameter. - - Note AWS supports parsing the Date header also, but this is not - currently supported here as it will require some format mangling - So the X-Amz-Date value must be YYYYMMDDTHHMMSSZ format, then it - can be used to match against the YYYYMMDD format provided in the - credential scope. - see: - http://docs.aws.amazon.com/general/latest/gr/ - sigv4-date-handling.html - """ - try: - return headers['X-Amz-Date'] - except KeyError: - return params.get('X-Amz-Date') - - def canonical_header_str(): - # Get the list of headers to include, from either - # - the Authorization header (SignedHeaders key) - # - the X-Amz-SignedHeaders query parameter - headers_lower = dict((k.lower().strip(), v.strip()) - for (k, v) in headers.items()) - - # Boto versions < 2.9.3 strip the port component of the host:port - # header, so detect the user-agent via the header and strip the - # port if we detect an old boto version. FIXME: remove when all - # distros package boto >= 2.9.3, this is a transitional workaround - user_agent = headers_lower.get('user-agent', '') - strip_port = re.match('Boto/2\.[0-9]\.[0-2]', user_agent) - - header_list = [] - sh_str = auth_param('SignedHeaders') - for h in sh_str.split(';'): - if h not in headers_lower: - continue - - if h == 'host' and strip_port: - header_list.append('%s:%s' % - (h, headers_lower[h].split(':')[0])) - continue - - header_list.append('%s:%s' % (h, headers_lower[h])) - return '\n'.join(header_list) + '\n' - - def canonical_query_str(verb, params): - # POST requests pass parameters in through the request body - canonical_qs = '' - if verb.upper() != 'POST': - canonical_qs = self._canonical_qs(params) - return canonical_qs - - # Create canonical request: - # http://docs.aws.amazon.com/general/latest/gr/ - # sigv4-create-canonical-request.html - # Get parameters and headers in expected string format - cr = "\n".join((verb.upper(), path, - canonical_query_str(verb, params), - canonical_header_str(), - auth_param('SignedHeaders'), - body_hash)) - - # Check the date, reject any request where the X-Amz-Date doesn't - # match the credential scope - credential = auth_param('Credential') - credential_split = credential.split('/') - credential_scope = '/'.join(credential_split[1:]) - credential_date = credential_split[1] - param_date = date_param() - if not param_date.startswith(credential_date): - raise Exception(_('Request date mismatch error')) - - # Create the string to sign - # http://docs.aws.amazon.com/general/latest/gr/ - # sigv4-create-string-to-sign.html - cr = cr.encode('utf-8') - string_to_sign = '\n'.join(('AWS4-HMAC-SHA256', - param_date, - credential_scope, - hashlib.sha256(cr).hexdigest())) - - # Calculate the derived key, this requires a datestamp, region - # and service, which can be extracted from the credential scope - (req_region, req_service) = credential_split[2:4] - s_key = signature_key(credential_date, req_region, req_service) - # Finally calculate the signature! - signature = hmac.new(s_key, self._get_utf8_value(string_to_sign), - hashlib.sha256).hexdigest() - return signature diff --git a/keystoneclient/discover.py b/keystoneclient/discover.py deleted file mode 100644 index 823c94cd..00000000 --- a/keystoneclient/discover.py +++ /dev/null @@ -1,364 +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. - -import warnings - -from debtcollector import removals -from keystoneauth1 import plugin -from positional import positional - -from keystoneclient import _discover -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import session as client_session -from keystoneclient.v2_0 import client as v2_client -from keystoneclient.v3 import client as v3_client - - -_CLIENT_VERSIONS = {2: v2_client.Client, - 3: v3_client.Client} - - -# functions needed from the private file that can be made public - -def normalize_version_number(version): - """Turn a version representation into a tuple. - - Takes a string, tuple or float which represent version formats we can - handle and converts them into a (major, minor) version tuple that we can - actually use for discovery. - - e.g. 'v3.3' gives (3, 3) - 3.1 gives (3, 1) - - :param version: Inputted version number to try and convert. - - :returns: A usable version tuple - :rtype: tuple - - :raises TypeError: if the inputted version cannot be converted to tuple. - """ - return _discover.normalize_version_number(version) - - -def version_match(required, candidate): - """Test that an available version satisfies the required version. - - To be suitable a version must be of the same major version as required - and be at least a match in minor/patch level. - - eg. 3.3 is a match for a required 3.1 but 4.1 is not. - - :param tuple required: the version that must be met. - :param tuple candidate: the version to test against required. - - :returns: True if candidate is suitable False otherwise. - :rtype: bool - """ - return _discover.version_match(required, candidate) - - -def available_versions(url, session=None, **kwargs): - """Retrieve raw version data from a url.""" - if not session: - session = client_session.Session._construct(kwargs) - - return _discover.get_version_data(session, url) - - -class Discover(_discover.Discover): - """A means to discover and create clients. - - Clients are created depending on the supported API versions on the server. - - Querying the server is done on object creation and every subsequent method - operates upon the data that was retrieved. - - The connection parameters associated with this method are the same format - and name as those used by a client (see - :py:class:`keystoneclient.v2_0.client.Client` and - :py:class:`keystoneclient.v3.client.Client`). If not overridden in - subsequent methods they will also be what is passed to the constructed - client. - - In the event that auth_url and endpoint is provided then auth_url will be - used in accordance with how the client operates. - - .. warning:: - - Creating an instance of this class without using the session argument - is deprecated as of the 1.7.0 release and may be removed in the 2.0.0 - release. - - :param session: A session object that will be used for communication. - Clients will also be constructed with this session. - :type session: keystoneclient.session.Session - :param string auth_url: Identity service endpoint for authorization. - (optional) - :param string endpoint: A user-supplied endpoint URL for the identity - service. (optional) - :param string original_ip: The original IP of the requesting user which - will be sent to identity service in a - 'Forwarded' header. (optional) This is ignored - if a session is provided. Deprecated as of the - 1.7.0 release and may be removed in the 2.0.0 - release. - :param boolean debug: Enables debug logging of all request and responses to - the identity service. default False (optional) - This is ignored if a session is provided. Deprecated - as of the 1.7.0 release and may be removed in the - 2.0.0 release. - :param string cacert: Path to the Privacy Enhanced Mail (PEM) file which - contains the trusted authority X.509 certificates - needed to established SSL connection with the - identity service. (optional) This is ignored if a - session is provided. Deprecated as of the 1.7.0 - release and may be removed in the 2.0.0 release. - :param string key: Path to the Privacy Enhanced Mail (PEM) file which - contains the unencrypted client private key needed to - established two-way SSL connection with the identity - service. (optional) This is ignored if a session is - provided. Deprecated as of the 1.7.0 release and may be - removed in the 2.0.0 release. - :param string cert: Path to the Privacy Enhanced Mail (PEM) file which - contains the corresponding X.509 client certificate - needed to established two-way SSL connection with the - identity service. (optional) This is ignored if a - session is provided. Deprecated as of the 1.7.0 release - and may be removed in the 2.0.0 release. - :param boolean insecure: Does not perform X.509 certificate validation when - establishing SSL connection with identity service. - default: False (optional) This is ignored if a - session is provided. Deprecated as of the 1.7.0 - release and may be removed in the 2.0.0 release. - :param bool authenticated: Should a token be used to perform the initial - discovery operations. default: None (attach a - token if an auth plugin is available). - - """ - - @positional(2) - def __init__(self, session=None, authenticated=None, **kwargs): - if not session: - warnings.warn( - 'Constructing a Discover instance without using a session is ' - 'deprecated as of the 1.7.0 release and may be removed in the ' - '2.0.0 release.', DeprecationWarning) - session = client_session.Session._construct(kwargs) - kwargs['session'] = session - - url = None - endpoint = kwargs.pop('endpoint', None) - auth_url = kwargs.pop('auth_url', None) - - if endpoint: - self._use_endpoint = True - url = endpoint - elif auth_url: - self._use_endpoint = False - url = auth_url - elif session.auth: - self._use_endpoint = False - url = session.get_endpoint(interface=plugin.AUTH_INTERFACE) - - if not url: - raise exceptions.DiscoveryFailure( - _('Not enough information to determine URL. Provide' - ' either a Session, or auth_url or endpoint')) - - self._client_kwargs = kwargs - super(Discover, self).__init__(session, url, - authenticated=authenticated) - - @removals.remove(message='Use raw_version_data instead.', version='1.7.0', - removal_version='2.0.0') - def available_versions(self, **kwargs): - """Return a list of identity APIs available on the server. - - The list returned includes the data associated with them. - - .. warning:: - - This method is deprecated as of the 1.7.0 release in favor of - :meth:`raw_version_data` and may be removed in the 2.0.0 release. - - :param bool unstable: Accept endpoints not marked 'stable'. (optional) - Equates to setting allow_experimental - and allow_unknown to True. - :param bool allow_experimental: Allow experimental version endpoints. - :param bool allow_deprecated: Allow deprecated version endpoints. - :param bool allow_unknown: Allow endpoints with an unrecognised status. - - :returns: A List of dictionaries as presented by the server. Each dict - will contain the version and the URL to use for the version. - It is a direct representation of the layout presented by the - identity API. - """ - return self.raw_version_data(**kwargs) - - @removals.removed_kwarg( - 'unstable', - message='Use allow_experimental and allow_unknown instead.', - version='1.7.0', removal_version='2.0.0') - def raw_version_data(self, unstable=False, **kwargs): - """Get raw version information from URL. - - Raw data indicates that only minimal validation processing is performed - on the data, so what is returned here will be the data in the same - format it was received from the endpoint. - - :param bool unstable: equates to setting allow_experimental and - allow_unknown. This argument is deprecated as of - the 1.7.0 release and may be removed in the 2.0.0 - release. - :param bool allow_experimental: Allow experimental version endpoints. - :param bool allow_deprecated: Allow deprecated version endpoints. - :param bool allow_unknown: Allow endpoints with an unrecognised status. - - :returns: The endpoints returned from the server that match the - criteria. - :rtype: List - - Example:: - - >>> from keystoneclient import discover - >>> disc = discover.Discovery(auth_url='http://localhost:5000') - >>> disc.raw_version_data() - [{'id': 'v3.0', - 'links': [{'href': u'http://127.0.0.1:5000/v3/', - 'rel': u'self'}], - 'media-types': [ - {'base': 'application/json', - 'type': 'application/vnd.openstack.identity-v3+json'}, - {'base': 'application/xml', - 'type': 'application/vnd.openstack.identity-v3+xml'}], - 'status': 'stable', - 'updated': '2013-03-06T00:00:00Z'}, - {'id': 'v2.0', - 'links': [{'href': u'http://127.0.0.1:5000/v2.0/', - 'rel': u'self'}, - {'href': u'...', - 'rel': u'describedby', - 'type': u'application/pdf'}], - 'media-types': [ - {'base': 'application/json', - 'type': 'application/vnd.openstack.identity-v2.0+json'}, - {'base': 'application/xml', - 'type': 'application/vnd.openstack.identity-v2.0+xml'}], - 'status': 'stable', - 'updated': '2013-03-06T00:00:00Z'}] - """ - if unstable: - kwargs.setdefault('allow_experimental', True) - kwargs.setdefault('allow_unknown', True) - - return super(Discover, self).raw_version_data(**kwargs) - - def _calculate_version(self, version, unstable): - version_data = None - - if version: - version_data = self.data_for(version) - else: - # if no version specified pick the latest one - all_versions = self.version_data(unstable=unstable) - if all_versions: - version_data = all_versions[-1] - - if not version_data: - msg = _('Could not find a suitable endpoint') - - if version: - msg = _('Could not find a suitable endpoint for client ' - 'version: %s') % str(version) - - raise exceptions.VersionNotAvailable(msg) - - return version_data - - def _create_client(self, version_data, **kwargs): - # Get the client for the version requested that was returned - try: - client_class = _CLIENT_VERSIONS[version_data['version'][0]] - except KeyError: - version = '.'.join(str(v) for v in version_data['version']) - msg = _('No client available for version: %s') % version - raise exceptions.DiscoveryFailure(msg) - - # kwargs should take priority over stored kwargs. - for k, v in self._client_kwargs.items(): - kwargs.setdefault(k, v) - - # restore the url to either auth_url or endpoint depending on what - # was initially given - if self._use_endpoint: - kwargs['auth_url'] = None - kwargs['endpoint'] = version_data['url'] - else: - kwargs['auth_url'] = version_data['url'] - kwargs['endpoint'] = None - - return client_class(**kwargs) - - def create_client(self, version=None, unstable=False, **kwargs): - """Factory function to create a new identity service client. - - :param tuple version: The required version of the identity API. If - specified the client will be selected such that - the major version is equivalent and an endpoint - provides at least the specified minor version. - For example to specify the 3.1 API use (3, 1). - (optional) - :param bool unstable: Accept endpoints not marked 'stable'. (optional) - :param kwargs: Additional arguments will override those provided to - this object's constructor. - - :returns: An instantiated identity client object. - - :raises keystoneclient.exceptions.DiscoveryFailure: if the server - response is invalid - :raises keystoneclient.exceptions.VersionNotAvailable: if a suitable - client cannot be found. - """ - version_data = self._calculate_version(version, unstable) - return self._create_client(version_data, **kwargs) - - -def add_catalog_discover_hack(service_type, old, new): - """Add a version removal rule for a particular service. - - Originally deployments of OpenStack would contain a versioned endpoint in - the catalog for different services. E.g. an identity service might look - like ``http://localhost:5000/v2.0``. This is a problem when we want to use - a different version like v3.0 as there is no way to tell where it is - located. We cannot simply change all service catalogs either so there must - be a way to handle the older style of catalog. - - This function adds a rule for a given service type that if part of the URL - matches a given regular expression in *old* then it will be replaced with - the *new* value. This will replace all instances of old with new. It should - therefore contain a regex anchor. - - For example the included rule states:: - - add_catalog_version_hack('identity', re.compile('/v2.0/?$'), '/') - - so if the catalog retrieves an *identity* URL that ends with /v2.0 or - /v2.0/ then it should replace it simply with / to fix the user's catalog. - - :param str service_type: The service type as defined in the catalog that - the rule will apply to. - :param re.RegexObject old: The regular expression to search for and replace - if found. - :param str new: The new string to replace the pattern with. - """ - _discover._VERSION_HACKS.add_discover_hack(service_type, old, new) diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py deleted file mode 100644 index 5b06be9b..00000000 --- a/keystoneclient/exceptions.py +++ /dev/null @@ -1,437 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 Nebula, Inc. -# -# 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. -"""Exception definitions.""" - -from keystoneauth1 import exceptions as _exc - -from keystoneclient.i18n import _ - - -ClientException = _exc.ClientException -"""The base exception class for all exceptions this library raises. - -An alias of :py:exc:`keystoneauth1.exceptions.base.ClientException` -""" - -ConnectionError = _exc.ConnectionError -"""Cannot connect to API service. - -An alias of :py:exc:`keystoneauth1.exceptions.connection.ConnectionError` -""" - -ConnectionRefused = _exc.ConnectFailure -"""Connection refused while trying to connect to API service. - -An alias of :py:exc:`keystoneauth1.exceptions.connection.ConnectFailure` -""" - -SSLError = _exc.SSLError -"""An SSL error occurred. - -An alias of :py:exc:`keystoneauth1.exceptions.connection.SSLError` -""" - -AuthorizationFailure = _exc.AuthorizationFailure -"""Cannot authorize API client. - -An alias of :py:exc:`keystoneauth1.exceptions.auth.AuthorizationFailure` -""" - - -class ValidationError(ClientException): - """Error in validation on API client side.""" - - pass - - -class UnsupportedVersion(ClientException): - """User is trying to use an unsupported version of the API.""" - - pass - - -class CommandError(ClientException): - """Error in CLI tool.""" - - pass - - -class AuthPluginOptionsMissing(AuthorizationFailure): - """Auth plugin misses some options.""" - - def __init__(self, opt_names): - super(AuthPluginOptionsMissing, self).__init__( - _("Authentication failed. Missing options: %s") % - ", ".join(opt_names)) - self.opt_names = opt_names - - -class AuthSystemNotFound(AuthorizationFailure): - """User has specified an AuthSystem that is not installed.""" - - def __init__(self, auth_system): - super(AuthSystemNotFound, self).__init__( - _("AuthSystemNotFound: %r") % auth_system) - self.auth_system = auth_system - - -class NoUniqueMatch(ClientException): - """Multiple entities found instead of one.""" - - pass - - -EndpointException = _exc.CatalogException -"""Something is rotten in Service Catalog. - -An alias of :py:exc:`keystoneauth1.exceptions.catalog.CatalogException` -""" - -EndpointNotFound = _exc.EndpointNotFound -"""Could not find requested endpoint in Service Catalog. - -An alias of :py:exc:`keystoneauth1.exceptions.catalog.EndpointNotFound` -""" - - -class AmbiguousEndpoints(EndpointException): - """Found more than one matching endpoint in Service Catalog.""" - - def __init__(self, endpoints=None): - super(AmbiguousEndpoints, self).__init__( - _("AmbiguousEndpoints: %r") % endpoints) - self.endpoints = endpoints - - -HttpError = _exc.HttpError -"""The base exception class for all HTTP exceptions. - -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpError` -""" - -HTTPClientError = _exc.HTTPClientError -"""Client-side HTTP error. - -Exception for cases in which the client seems to have erred. -An alias of :py:exc:`keystoneauth1.exceptions.http.HTTPClientError` -""" - -HttpServerError = _exc.HttpServerError -"""Server-side HTTP error. - -Exception for cases in which the server is aware that it has -erred or is incapable of performing the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpServerError` -""" - - -class HTTPRedirection(HttpError): - """HTTP Redirection.""" - - message = _("HTTP Redirection") - - -class MultipleChoices(HTTPRedirection): - """HTTP 300 - Multiple Choices. - - Indicates multiple options for the resource that the client may follow. - """ - - http_status = 300 - message = _("Multiple Choices") - - -BadRequest = _exc.BadRequest -"""HTTP 400 - Bad Request. - -The request cannot be fulfilled due to bad syntax. -An alias of :py:exc:`keystoneauth1.exceptions.http.BadRequest` -""" - -Unauthorized = _exc.Unauthorized -"""HTTP 401 - Unauthorized. - -Similar to 403 Forbidden, but specifically for use when authentication -is required and has failed or has not yet been provided. -An alias of :py:exc:`keystoneauth1.exceptions.http.Unauthorized` -""" - -PaymentRequired = _exc.PaymentRequired -"""HTTP 402 - Payment Required. - -Reserved for future use. -An alias of :py:exc:`keystoneauth1.exceptions.http.PaymentRequired` -""" - -Forbidden = _exc.Forbidden -"""HTTP 403 - Forbidden. - -The request was a valid request, but the server is refusing to respond -to it. -An alias of :py:exc:`keystoneauth1.exceptions.http.Forbidden` -""" - -NotFound = _exc.NotFound -"""HTTP 404 - Not Found. - -The requested resource could not be found but may be available again -in the future. -An alias of :py:exc:`keystoneauth1.exceptions.http.NotFound` -""" - -MethodNotAllowed = _exc.MethodNotAllowed -"""HTTP 405 - Method Not Allowed. - -A request was made of a resource using a request method not supported -by that resource. -An alias of :py:exc:`keystoneauth1.exceptions.http.MethodNotAllowed` -""" - -NotAcceptable = _exc.NotAcceptable -"""HTTP 406 - Not Acceptable. - -The requested resource is only capable of generating content not -acceptable according to the Accept headers sent in the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.NotAcceptable` -""" - -ProxyAuthenticationRequired = _exc.ProxyAuthenticationRequired -"""HTTP 407 - Proxy Authentication Required. - -The client must first authenticate itself with the proxy. -An alias of :py:exc:`keystoneauth1.exceptions.http.ProxyAuthenticationRequired` -""" - -RequestTimeout = _exc.RequestTimeout -"""HTTP 408 - Request Timeout. - -The server timed out waiting for the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.RequestTimeout` -""" - -Conflict = _exc.Conflict -"""HTTP 409 - Conflict. - -Indicates that the request could not be processed because of conflict -in the request, such as an edit conflict. -An alias of :py:exc:`keystoneauth1.exceptions.http.Conflict` -""" - -Gone = _exc.Gone -"""HTTP 410 - Gone. - -Indicates that the resource requested is no longer available and will -not be available again. -An alias of :py:exc:`keystoneauth1.exceptions.http.Gone` -""" - -LengthRequired = _exc.LengthRequired -"""HTTP 411 - Length Required. - -The request did not specify the length of its content, which is -required by the requested resource. -An alias of :py:exc:`keystoneauth1.exceptions.http.LengthRequired` -""" - -PreconditionFailed = _exc.PreconditionFailed -"""HTTP 412 - Precondition Failed. - -The server does not meet one of the preconditions that the requester -put on the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.PreconditionFailed` -""" - -RequestEntityTooLarge = _exc.RequestEntityTooLarge -"""HTTP 413 - Request Entity Too Large. - -The request is larger than the server is willing or able to process. -An alias of :py:exc:`keystoneauth1.exceptions.http.RequestEntityTooLarge` -""" - -RequestUriTooLong = _exc.RequestUriTooLong -"""HTTP 414 - Request-URI Too Long. - -The URI provided was too long for the server to process. -An alias of :py:exc:`keystoneauth1.exceptions.http.RequestUriTooLong` -""" - -UnsupportedMediaType = _exc.UnsupportedMediaType -"""HTTP 415 - Unsupported Media Type. - -The request entity has a media type which the server or resource does -not support. -An alias of :py:exc:`keystoneauth1.exceptions.http.UnsupportedMediaType` -""" - -RequestedRangeNotSatisfiable = _exc.RequestedRangeNotSatisfiable -"""HTTP 416 - Requested Range Not Satisfiable. - -The client has asked for a portion of the file, but the server cannot -supply that portion. -An alias of -:py:exc:`keystoneauth1.exceptions.http.RequestedRangeNotSatisfiable` -""" - -ExpectationFailed = _exc.ExpectationFailed -"""HTTP 417 - Expectation Failed. - -The server cannot meet the requirements of the Expect request-header field. -An alias of :py:exc:`keystoneauth1.exceptions.http.ExpectationFailed` -""" - -UnprocessableEntity = _exc.UnprocessableEntity -"""HTTP 422 - Unprocessable Entity. - -The request was well-formed but was unable to be followed due to semantic -errors. -An alias of :py:exc:`keystoneauth1.exceptions.http.UnprocessableEntity` -""" - -InternalServerError = _exc.InternalServerError -"""HTTP 500 - Internal Server Error. - -A generic error message, given when no more specific message is suitable. -An alias of :py:exc:`keystoneauth1.exceptions.http.InternalServerError` -""" - -HttpNotImplemented = _exc.HttpNotImplemented -"""HTTP 501 - Not Implemented. - -The server either does not recognize the request method, or it lacks -the ability to fulfill the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpNotImplemented` -""" - -BadGateway = _exc.BadGateway -"""HTTP 502 - Bad Gateway. - -The server was acting as a gateway or proxy and received an invalid -response from the upstream server. -An alias of :py:exc:`keystoneauth1.exceptions.http.BadGateway` -""" - -ServiceUnavailable = _exc.ServiceUnavailable -"""HTTP 503 - Service Unavailable. - -The server is currently unavailable. -An alias of :py:exc:`keystoneauth1.exceptions.http.ServiceUnavailable` -""" - -GatewayTimeout = _exc.GatewayTimeout -"""HTTP 504 - Gateway Timeout. - -The server was acting as a gateway or proxy and did not receive a timely -response from the upstream server. -An alias of :py:exc:`keystoneauth1.exceptions.http.GatewayTimeout` -""" - -HttpVersionNotSupported = _exc.HttpVersionNotSupported -"""HTTP 505 - HttpVersion Not Supported. - -The server does not support the HTTP protocol version used in the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpVersionNotSupported` -""" - -from_response = _exc.from_response -"""Return an instance of :class:`HttpError` or subclass based on response. - -An alias of :py:func:`keystoneauth1.exceptions.http.from_response` -""" - - -# NOTE(akurilin): This alias should be left here to support backwards -# compatibility until we are sure that usage of these exceptions in -# projects is correct. -HTTPNotImplemented = HttpNotImplemented -Timeout = RequestTimeout -HTTPError = HttpError - - -class CertificateConfigError(Exception): - """Error reading the certificate.""" - - def __init__(self, output): - self.output = output - msg = _('Unable to load certificate.') - super(CertificateConfigError, self).__init__(msg) - - -class CMSError(Exception): - """Error reading the certificate.""" - - def __init__(self, output): - self.output = output - msg = _('Unable to sign or verify data.') - super(CMSError, self).__init__(msg) - -EmptyCatalog = _exc.EmptyCatalog -"""The service catalog is empty. - -An alias of :py:exc:`keystoneauth1.exceptions.catalog.EmptyCatalog` -""" - -DiscoveryFailure = _exc.DiscoveryFailure -"""Discovery of client versions failed. - -An alias of :py:exc:`keystoneauth1.exceptions.discovery.DiscoveryFailure` -""" - -VersionNotAvailable = _exc.VersionNotAvailable -"""Discovery failed as the version you requested is not available. - -An alias of :py:exc:`keystoneauth1.exceptions.discovery.VersionNotAvailable` -""" - - -class MethodNotImplemented(ClientException): - """Method not implemented by the keystoneclient API.""" - -MissingAuthPlugin = _exc.MissingAuthPlugin -"""An authenticated request is required but no plugin available. - -An alias of :py:exc:`keystoneauth1.exceptions.auth_plugins.MissingAuthPlugin` -""" - -NoMatchingPlugin = _exc.NoMatchingPlugin -"""There were no auth plugins that could be created from the parameters -provided. - -An alias of :py:exc:`keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin` -""" - - -class UnsupportedParameters(ClientException): - """A parameter that was provided or returned is not supported. - - :param List(str) names: Names of the unsupported parameters. - - .. py:attribute:: names - - Names of the unsupported parameters. - """ - - def __init__(self, names): - self.names = names - - m = _('The following parameters were given that are unsupported: %s') - super(UnsupportedParameters, self).__init__(m % ', '.join(self.names)) - - -class InvalidResponse(ClientException): - """The response from the server is not valid for this request.""" - - def __init__(self, response): - super(InvalidResponse, self).__init__() - self.response = response diff --git a/keystoneclient/fixture/__init__.py b/keystoneclient/fixture/__init__.py deleted file mode 100644 index 768f9691..00000000 --- a/keystoneclient/fixture/__init__.py +++ /dev/null @@ -1,56 +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. - -""" -Produce keystone compliant structures for testing. - -The generators in this directory produce keystone compliant structures for -use in testing. -They should be considered part of the public API because they may be relied -upon to generate test tokens for other clients. However they should never be -imported into the main client (keystoneclient or other). Because of this there -may be dependencies from this module on libraries that are only available in -testing. - -.. warning:: - - The keystoneclient.fixture package is deprecated in favor of - keystoneauth1.fixture and will not be supported. - -""" - -import warnings - -from keystoneclient.fixture.discovery import * # noqa -from keystoneclient.fixture import exception -from keystoneclient.fixture import v2 -from keystoneclient.fixture import v3 - - -warnings.warn( - "The keystoneclient.fixture package is deprecated in favor of " - "keystoneauth1.fixture and will not be supported.", DeprecationWarning) - - -FixtureValidationError = exception.FixtureValidationError -V2Token = v2.Token -V3Token = v3.Token -V3FederationToken = v3.V3FederationToken - -__all__ = ('DiscoveryList', - 'FixtureValidationError', - 'V2Discovery', - 'V3Discovery', - 'V2Token', - 'V3Token', - 'V3FederationToken', - ) diff --git a/keystoneclient/fixture/discovery.py b/keystoneclient/fixture/discovery.py deleted file mode 100644 index e664d283..00000000 --- a/keystoneclient/fixture/discovery.py +++ /dev/null @@ -1,38 +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 keystoneauth1.fixture import discovery - - -__all__ = ('DiscoveryList', - 'V2Discovery', - 'V3Discovery', - ) - - -V2Discovery = discovery.V2Discovery -"""A Version element for a V2 identity service endpoint. - -An alias of :py:exc:`keystoneauth1.fixture.discovery.V2Discovery` -""" - -V3Discovery = discovery.V3Discovery -"""A Version element for a V3 identity service endpoint. - -An alias of :py:exc:`keystoneauth1.fixture.discovery.V3Discovery` -""" - -DiscoveryList = discovery.DiscoveryList -"""A List of version elements. - -An alias of :py:exc:`keystoneauth1.fixture.discovery.DiscoveryList` -""" diff --git a/keystoneclient/fixture/exception.py b/keystoneclient/fixture/exception.py deleted file mode 100644 index 99e48763..00000000 --- a/keystoneclient/fixture/exception.py +++ /dev/null @@ -1,20 +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 keystoneauth1.fixture import exception - - -FixtureValidationError = exception.FixtureValidationError -"""The token you created is not legitimate. - -An alias of :py:exc:`keystoneauth1.fixture.exception.FixtureValidationError`` -""" diff --git a/keystoneclient/fixture/v2.py b/keystoneclient/fixture/v2.py deleted file mode 100644 index 9fbf4e00..00000000 --- a/keystoneclient/fixture/v2.py +++ /dev/null @@ -1,20 +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 keystoneauth1.fixture import v2 - - -Token = v2.Token -"""A V2 Keystone token that can be used for testing. - -An alias of :py:exc:`keystoneauth1.fixture.v2.Token` -""" diff --git a/keystoneclient/fixture/v3.py b/keystoneclient/fixture/v3.py deleted file mode 100644 index 596f3e2b..00000000 --- a/keystoneclient/fixture/v3.py +++ /dev/null @@ -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 keystoneauth1.fixture import v3 - - -Token = v3.Token -"""A V3 Keystone token that can be used for testing. - -An alias of :py:exc:`keystoneauth1.fixture.v3.Token` -""" - -V3FederationToken = v3.V3FederationToken -"""A V3 Keystone Federation token that can be used for testing. - -An alias of :py:exc:`keystoneauth1.fixture.v3.V3FederationToken` -""" diff --git a/keystoneclient/generic/__init__.py b/keystoneclient/generic/__init__.py deleted file mode 100644 index 74569210..00000000 --- a/keystoneclient/generic/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ - -__all__ = ( - 'client', -) diff --git a/keystoneclient/generic/client.py b/keystoneclient/generic/client.py deleted file mode 100644 index e6b58339..00000000 --- a/keystoneclient/generic/client.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2010 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from debtcollector import removals -from six.moves.urllib import parse as urlparse - -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient.i18n import _ - - -_logger = logging.getLogger(__name__) - - -# NOTE(jamielennox): To be removed after Pike. -@removals.removed_class('keystoneclient.generic.client.Client', - message='Use keystoneauth discovery', - version='3.9.0', - removal_version='4.0.0') -class Client(httpclient.HTTPClient): - """Client for the OpenStack Keystone pre-version calls API. - - :param string endpoint: A user-supplied endpoint URL for the keystone - service. - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - - Example:: - - >>> from keystoneclient.generic import client - >>> root = client.Client(auth_url=KEYSTONE_URL) - >>> versions = root.discover() - ... - >>> from keystoneclient.v2_0 import client as v2client - >>> keystone = v2client.Client(auth_url=versions['v2.0']['url']) - ... - >>> user = keystone.users.get(USER_ID) - >>> user.delete() - - """ - - def __init__(self, endpoint=None, **kwargs): - """Initialize a new client for the Keystone v2.0 API.""" - super(Client, self).__init__(endpoint=endpoint, **kwargs) - self.endpoint = endpoint - - def discover(self, url=None): - """Discover Keystone servers and return API versions supported. - - :param url: optional url to test (without version) - - Returns:: - - { - 'message': 'Keystone found at http://127.0.0.1:5000/', - 'v2.0': { - 'status': 'beta', - 'url': 'http://127.0.0.1:5000/v2.0/', - 'id': 'v2.0' - }, - } - - """ - if url: - return self._check_keystone_versions(url) - else: - return self._local_keystone_exists() - - def _local_keystone_exists(self): - """Check if Keystone is available on default local port 35357.""" - results = self._check_keystone_versions("http://localhost:35357") - if results is None: - results = self._check_keystone_versions("https://localhost:35357") - return results - - def _check_keystone_versions(self, url): - """Call Keystone URL and detects the available API versions.""" - try: - resp, body = self._request(url, "GET", - headers={'Accept': - 'application/json'}) - # Multiple Choices status code is returned by the root - # identity endpoint, with references to one or more - # Identity API versions -- v3 spec - # some cases we get No Content - if resp.status_code in (200, 204, 300): - try: - results = {} - if 'version' in body: - results['message'] = _("Keystone found at %s") % url - version = body['version'] - # Stable/diablo incorrect format - id, status, version_url = ( - self._get_version_info(version, url)) - results[str(id)] = {"id": id, - "status": status, - "url": version_url} - return results - elif 'versions' in body: - # Correct format - results['message'] = _("Keystone found at %s") % url - for version in body['versions']['values']: - id, status, version_url = ( - self._get_version_info(version, url)) - results[str(id)] = {"id": id, - "status": status, - "url": version_url} - return results - else: - results['message'] = ( - _("Unrecognized response from %s") % url) - return results - except KeyError: - raise exceptions.AuthorizationFailure() - elif resp.status_code == 305: - return self._check_keystone_versions(resp['location']) - else: - raise exceptions.from_response(resp, "GET", url) - except Exception: - _logger.exception('Failed to detect available versions.') - - def discover_extensions(self, url=None): - """Discover Keystone extensions supported. - - :param url: optional url to test (should have a version in it) - - Returns:: - - { - 'message': 'Keystone extensions at http://127.0.0.1:35357/v2', - 'OS-KSEC2': 'OpenStack EC2 Credentials Extension', - } - - """ - if url: - return self._check_keystone_extensions(url) - - def _check_keystone_extensions(self, url): - """Call Keystone URL and detects the available extensions.""" - try: - if not url.endswith("/"): - url += '/' - resp, body = self._request("%sextensions" % url, "GET", - headers={'Accept': - 'application/json'}) - if resp.status_code in (200, 204): # some cases we get No Content - if 'extensions' in body and 'values' in body['extensions']: - # Parse correct format (per contract) - extensions = body['extensions']['values'] - elif 'extensions' in body: - # Support incorrect, but prevalent format - extensions = body['extensions'] - else: - return dict(message=( - _('Unrecognized extensions response from %s') % url)) - - return dict(self._get_extension_info(e) for e in extensions) - elif resp.status_code == 305: - return self._check_keystone_extensions(resp['location']) - else: - raise exceptions.from_response( - resp, "GET", "%sextensions" % url) - except Exception: - _logger.exception('Failed to check keystone extensions.') - - @staticmethod - def _get_version_info(version, root_url): - """Parse version information. - - :param version: a dict of a Keystone version response - :param root_url: string url used to construct - the version if no URL is provided. - :returns: tuple - (verionId, versionStatus, versionUrl) - """ - id = version['id'] - status = version['status'] - ref = urlparse.urljoin(root_url, id) - if 'links' in version: - for link in version['links']: - if link['rel'] == 'self': - ref = link['href'] - break - return (id, status, ref) - - @staticmethod - def _get_extension_info(extension): - """Parse extension information. - - :param extension: a dict of a Keystone extension response - :returns: tuple - (alias, name) - """ - alias = extension['alias'] - name = extension['name'] - return (alias, name) diff --git a/keystoneclient/httpclient.py b/keystoneclient/httpclient.py deleted file mode 100644 index e6813f32..00000000 --- a/keystoneclient/httpclient.py +++ /dev/null @@ -1,919 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Piston Cloud Computing, Inc. -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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. -"""OpenStack Client interface. Handles the REST calls and responses.""" - -import logging -import warnings - -from debtcollector import removals -from debtcollector import renames -from keystoneauth1 import adapter -from oslo_serialization import jsonutils -import pkg_resources -from positional import positional -import requests - -try: - import pickle # nosec(cjschaef): see bug 1534288 for details - - # NOTE(sdague): The conditional keyring import needs to only - # trigger if it's a version of keyring that's supported in global - # requirements. Update _min and _bad when that changes. - keyring_v = pkg_resources.parse_version( - pkg_resources.get_distribution("keyring").version) - keyring_min = pkg_resources.parse_version('5.5.1') - # This is a list of versions, e.g., pkg_resources.parse_version('3.3') - keyring_bad = [] - - if keyring_v >= keyring_min and keyring_v not in keyring_bad: - import keyring - else: - keyring = None -except (ImportError, pkg_resources.DistributionNotFound): - keyring = None - pickle = None - - -from keystoneclient import _discover -from keystoneclient import access -from keystoneclient.auth import base -from keystoneclient import baseclient -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import session as client_session - - -_logger = logging.getLogger(__name__) - -USER_AGENT = client_session.USER_AGENT -"""Default user agent string. - -This property is deprecated as of the 1.7.0 release in favor of -:data:`keystoneclient.session.USER_AGENT` and may be removed in the 2.0.0 -release. -""" - - -@removals.remove(message='Use keystoneclient.session.request instead.', - version='1.7.0', removal_version='2.0.0') -def request(*args, **kwargs): - """Make a request. - - This function is deprecated as of the 1.7.0 release in favor of - :func:`keystoneclient.session.request` and may be removed in the - 2.0.0 release. - """ - return client_session.request(*args, **kwargs) - - -class _FakeRequestSession(object): - """This object is a temporary hack that should be removed later. - - Keystoneclient has a cyclical dependency with its managers which is - preventing it from being cleaned up correctly. This is always bad but when - we switched to doing connection pooling this object wasn't getting cleaned - either and so we had left over TCP connections hanging around. - - Until we can fix the client cleanup we rollback the use of a requests - session and do individual connections like we used to. - """ - - def request(self, *args, **kwargs): - return requests.request(*args, **kwargs) - - -class _KeystoneAdapter(adapter.LegacyJsonAdapter): - """A wrapper layer to interface keystoneclient with a session. - - An adapter provides a generic interface between a client and the session to - provide client specific defaults. This object is passed to the managers. - Keystoneclient managers have some additional requirements of variables that - they expect to be present on the passed object. - - Subclass the existing adapter to provide those values that keystoneclient - managers expect. - """ - - @property - def user_id(self): - """Best effort to retrieve the user_id from the plugin. - - Some managers rely on being able to get the currently authenticated - user id. This is a problem when we are trying to abstract away the - details of an auth plugin. - - For example changing a user's password can require access to the - currently authenticated user_id. - - Perform a best attempt to fetch this data. It will work in the legacy - case and with identity plugins and be None otherwise which is the same - as the historical behavior. - """ - # the identity plugin case - try: - return self.session.auth.get_access(self.session).user_id - except AttributeError: # nosec(cjschaef): attempt legacy retrival, or - # return None - pass - - # there is a case that we explicitly allow (tested by our unit tests) - # that says you should be able to set the user_id on a legacy client - # and it should overwrite the one retrieved via authentication. If it's - # a legacy then self.session.auth is a client and we retrieve user_id. - try: - return self.session.auth.user_id - except AttributeError: # nosec(cjschaef): retrivals failed, return - # None - pass - - return None - - -class HTTPClient(baseclient.Client, base.BaseAuthPlugin): - """HTTP client. - - .. warning:: - - Creating an instance of this class without using the session argument - is deprecated as of the 1.7.0 release and may be removed in the 2.0.0 - release. - - :param string user_id: User ID for authentication. (optional) - :param string username: Username for authentication. (optional) - :param string user_domain_id: User's domain ID for authentication. - (optional) - :param string user_domain_name: User's domain name for authentication. - (optional) - :param string password: Password for authentication. (optional) - :param string domain_id: Domain ID for domain scoping. (optional) - :param string domain_name: Domain name for domain scoping. (optional) - :param string project_id: Project ID for project scoping. (optional) - :param string project_name: Project name for project scoping. (optional) - :param string project_domain_id: Project's domain ID for project scoping. - (optional) - :param string project_domain_name: Project's domain name for project - scoping. (optional) - :param string auth_url: Identity service endpoint for authorization. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - :param integer timeout: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param string endpoint: A user-supplied endpoint URL for the identity - service. Lazy-authentication is possible for API - service calls if endpoint is set at instantiation. - (optional) - :param string token: Token for authentication. (optional) - :param string cacert: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param string key: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param string cert: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param boolean insecure: This argument is deprecated as of the 1.7.0 - release in favor of session and may be removed in - the 2.0.0 release. (optional) - :param string original_ip: This argument is deprecated as of the 1.7.0 - release in favor of session and may be removed - in the 2.0.0 release. (optional) - :param dict auth_ref: To allow for consumers of the client to manage their - own caching strategy, you may initialize a client - with a previously captured auth_reference (token). If - there are keyword arguments passed that also exist in - auth_ref, the value from the argument will take - precedence. - :param boolean use_keyring: Enables caching auth_ref into keyring. - default: False (optional) - :param boolean force_new_token: Keyring related parameter, forces request - for new token. default: False (optional) - :param integer stale_duration: Gap in seconds to determine if token from - keyring is about to expire. default: 30 - (optional) - :param string tenant_name: Tenant name. (optional) The tenant_name keyword - argument is deprecated as of the 1.7.0 release - in favor of project_name and may be removed in - the 2.0.0 release. - :param string tenant_id: Tenant id. (optional) The tenant_id keyword - argument is deprecated as of the 1.7.0 release in - favor of project_id and may be removed in the - 2.0.0 release. - :param string trust_id: Trust ID for trust scoping. (optional) - :param object session: A Session object to be used for - communicating with the identity service. - :type session: keystoneclient.session.Session - :param string service_name: The default service_name for URL discovery. - default: None (optional) - :param string interface: The default interface for URL discovery. - default: admin (optional) - :param string endpoint_override: Always use this endpoint URL for requests - for this client. (optional) - :param auth: An auth plugin to use instead of the session one. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - :param string user_agent: The User-Agent string to set. - default: python-keystoneclient (optional) - :param int connect_retries: the maximum number of retries that should - be attempted for connection errors. - Default None - use session default which - is don't retry. (optional) - """ - - version = None - - @renames.renamed_kwarg('tenant_name', 'project_name', version='1.7.0', - removal_version='2.0.0') - @renames.renamed_kwarg('tenant_id', 'project_id', version='1.7.0', - removal_version='2.0.0') - @positional(enforcement=positional.WARN) - def __init__(self, username=None, tenant_id=None, tenant_name=None, - password=None, auth_url=None, region_name=None, endpoint=None, - token=None, auth_ref=None, use_keyring=False, - force_new_token=False, stale_duration=None, user_id=None, - user_domain_id=None, user_domain_name=None, domain_id=None, - domain_name=None, project_id=None, project_name=None, - project_domain_id=None, project_domain_name=None, - trust_id=None, session=None, service_name=None, - interface='admin', endpoint_override=None, auth=None, - user_agent=USER_AGENT, connect_retries=None, **kwargs): - # set baseline defaults - self.user_id = None - self.username = None - self.user_domain_id = None - self.user_domain_name = None - - self.domain_id = None - self.domain_name = None - - self.project_id = None - self.project_name = None - self.project_domain_id = None - self.project_domain_name = None - - self.auth_url = None - self._endpoint = None - self._management_url = None - - self.trust_id = None - - # if loading from a dictionary passed in via auth_ref, - # load values from AccessInfo parsing that dictionary - if auth_ref: - self.auth_ref = access.AccessInfo.factory(**auth_ref) - self.version = self.auth_ref.version - self.user_id = self.auth_ref.user_id - self.username = self.auth_ref.username - self.user_domain_id = self.auth_ref.user_domain_id - self.domain_id = self.auth_ref.domain_id - self.domain_name = self.auth_ref.domain_name - self.project_id = self.auth_ref.project_id - self.project_name = self.auth_ref.project_name - self.project_domain_id = self.auth_ref.project_domain_id - auth_urls = self.auth_ref.service_catalog.get_urls( - service_type='identity', endpoint_type='public', - region_name=region_name) - self.auth_url = auth_urls[0] - management_urls = self.auth_ref.service_catalog.get_urls( - service_type='identity', endpoint_type='admin', - region_name=region_name) - self._management_url = management_urls[0] - self.auth_token_from_user = self.auth_ref.auth_token - self.trust_id = self.auth_ref.trust_id - - # TODO(blk-u): Using self.auth_ref.service_catalog._region_name is - # deprecated and this code must be removed when the property is - # actually removed. - if self.auth_ref.has_service_catalog() and not region_name: - region_name = self.auth_ref.service_catalog._region_name - - else: - self.auth_ref = None - - # allow override of the auth_ref defaults from explicit - # values provided to the client - - # apply deprecated variables first, so modern variables override them - if tenant_id: - self.project_id = tenant_id - if tenant_name: - self.project_name = tenant_name - - # user-related attributes - self.password = password - if user_id: - self.user_id = user_id - if username: - self.username = username - if user_domain_id: - self.user_domain_id = user_domain_id - elif not (user_id or user_domain_name): - self.user_domain_id = 'default' - if user_domain_name: - self.user_domain_name = user_domain_name - - # domain-related attributes - if domain_id: - self.domain_id = domain_id - if domain_name: - self.domain_name = domain_name - - # project-related attributes - if project_id: - self.project_id = project_id - if project_name: - self.project_name = project_name - if project_domain_id: - self.project_domain_id = project_domain_id - elif not (project_id or project_domain_name): - self.project_domain_id = 'default' - if project_domain_name: - self.project_domain_name = project_domain_name - - # trust-related attributes - if trust_id: - self.trust_id = trust_id - - # endpoint selection - if auth_url: - self.auth_url = auth_url.rstrip('/') - if token: - self.auth_token_from_user = token - else: - self.auth_token_from_user = None - if endpoint: - self._endpoint = endpoint.rstrip('/') - self._auth_token = None - - if not session: - - warnings.warn( - 'Constructing an HTTPClient instance without using a session ' - 'is deprecated as of the 1.7.0 release and may be removed in ' - 'the 2.0.0 release.', DeprecationWarning) - - kwargs['session'] = _FakeRequestSession() - session = client_session.Session._construct(kwargs) - session.auth = self - - self.session = session - self.domain = '' - - # NOTE(jamielennox): unfortunately we can't just use **kwargs here as - # it would incompatibly limit the kwargs that can be passed to __init__ - # try and keep this list in sync with adapter.Adapter.__init__ - version = ( - _discover.normalize_version_number(self.version) if self.version - else None) - self._adapter = _KeystoneAdapter(session, - service_type='identity', - service_name=service_name, - interface=interface, - region_name=region_name, - endpoint_override=endpoint_override, - version=version, - auth=auth, - user_agent=user_agent, - connect_retries=connect_retries) - - # keyring setup - if use_keyring and keyring is None: - _logger.warning('Failed to load keyring modules.') - self.use_keyring = use_keyring and keyring is not None - self.force_new_token = force_new_token - self.stale_duration = stale_duration or access.STALE_TOKEN_DURATION - self.stale_duration = int(self.stale_duration) - - def get_token(self, session, **kwargs): - return self.auth_token - - @property - def auth_token(self): - if self._auth_token: - return self._auth_token - if self.auth_ref: - if self.auth_ref.will_expire_soon(self.stale_duration): - self.authenticate() - return self.auth_ref.auth_token - if self.auth_token_from_user: - return self.auth_token_from_user - - def get_endpoint(self, session, interface=None, **kwargs): - if interface == 'public' or interface is base.AUTH_INTERFACE: - return self.auth_url - else: - return self.management_url - - def get_user_id(self, session, **kwargs): - return self.auth_ref.user_id - - def get_project_id(self, session, **kwargs): - return self.auth_ref.project_id - - @auth_token.setter - def auth_token(self, value): - """Override the auth_token. - - If an application sets auth_token explicitly then it will always be - used and override any past or future retrieved token. - """ - self._auth_token = value - - @auth_token.deleter - def auth_token(self): - self._auth_token = None - self.auth_token_from_user = None - - @property - def service_catalog(self): - """Return this client's service catalog.""" - try: - return self.auth_ref.service_catalog - except AttributeError: - return None - - def has_service_catalog(self): - """Return True if this client provides a service catalog.""" - return self.auth_ref and self.auth_ref.has_service_catalog() - - @property - def tenant_id(self): - """Provide read-only backwards compatibility for tenant_id. - - .. warning:: - - This is deprecated as of the 1.7.0 release in favor of project_id - and may be removed in the 2.0.0 release. - """ - warnings.warn( - 'tenant_id is deprecated as of the 1.7.0 release in favor of ' - 'project_id and may be removed in the 2.0.0 release.', - DeprecationWarning) - - return self.project_id - - @property - def tenant_name(self): - """Provide read-only backwards compatibility for tenant_name. - - .. warning:: - - This is deprecated as of the 1.7.0 release in favor of project_name - and may be removed in the 2.0.0 release. - """ - warnings.warn( - 'tenant_name is deprecated as of the 1.7.0 release in favor of ' - 'project_name and may be removed in the 2.0.0 release.', - DeprecationWarning) - - return self.project_name - - @positional(enforcement=positional.WARN) - def authenticate(self, username=None, password=None, tenant_name=None, - tenant_id=None, auth_url=None, token=None, - user_id=None, domain_name=None, domain_id=None, - project_name=None, project_id=None, user_domain_id=None, - user_domain_name=None, project_domain_id=None, - project_domain_name=None, trust_id=None, - region_name=None): - """Authenticate user. - - Uses the data provided at instantiation to authenticate against - the Identity server. This may use either a username and password - or token for authentication. If a tenant name or id was provided - then the resulting authenticated client will be scoped to that - tenant and contain a service catalog of available endpoints. - - With the v2.0 API, if a tenant name or ID is not provided, the - authentication token returned will be 'unscoped' and limited in - capabilities until a fully-scoped token is acquired. - - With the v3 API, if a domain name or id was provided then the resulting - authenticated client will be scoped to that domain. If a project name - or ID is not provided, and the authenticating user has a default - project configured, the authentication token returned will be 'scoped' - to the default project. Otherwise, the authentication token returned - will be 'unscoped' and limited in capabilities until a fully-scoped - token is acquired. - - With the v3 API, with the OS-TRUST extension enabled, the trust_id can - be provided to allow project-specific role delegation between users - - If successful, sets the self.auth_ref and self.auth_token with - the returned token. If not already set, will also set - self.management_url from the details provided in the token. - - :returns: ``True`` if authentication was successful. - :raises keystoneclient.exceptions.AuthorizationFailure: if unable to - authenticate or validate the existing authorization token - :raises keystoneclient.exceptions.ValueError: if insufficient - parameters are used. - - If keyring is used, token is retrieved from keyring instead. - Authentication will only be necessary if any of the following - conditions are met: - - * keyring is not used - * if token is not found in keyring - * if token retrieved from keyring is expired or about to - expired (as determined by stale_duration) - * if force_new_token is true - - """ - auth_url = auth_url or self.auth_url - user_id = user_id or self.user_id - username = username or self.username - password = password or self.password - - user_domain_id = user_domain_id or self.user_domain_id - user_domain_name = user_domain_name or self.user_domain_name - domain_id = domain_id or self.domain_id - domain_name = domain_name or self.domain_name - project_id = project_id or tenant_id or self.project_id - project_name = project_name or tenant_name or self.project_name - project_domain_id = project_domain_id or self.project_domain_id - project_domain_name = project_domain_name or self.project_domain_name - - trust_id = trust_id or self.trust_id - region_name = region_name or self._adapter.region_name - - if not token: - token = self.auth_token_from_user - if (not token and self.auth_ref and not - self.auth_ref.will_expire_soon(self.stale_duration)): - token = self.auth_ref.auth_token - - kwargs = { - 'auth_url': auth_url, - 'user_id': user_id, - 'username': username, - 'user_domain_id': user_domain_id, - 'user_domain_name': user_domain_name, - 'domain_id': domain_id, - 'domain_name': domain_name, - 'project_id': project_id, - 'project_name': project_name, - 'project_domain_id': project_domain_id, - 'project_domain_name': project_domain_name, - 'token': token, - 'trust_id': trust_id, - } - (keyring_key, auth_ref) = self.get_auth_ref_from_keyring(**kwargs) - new_token_needed = False - if auth_ref is None or self.force_new_token: - new_token_needed = True - kwargs['password'] = password - resp = self.get_raw_token_from_identity_service(**kwargs) - - if isinstance(resp, access.AccessInfo): - self.auth_ref = resp - else: - self.auth_ref = access.AccessInfo.factory(*resp) - - # NOTE(jamielennox): The original client relies on being able to - # push the region name into the service catalog but new auth - # it in. - if region_name: - self.auth_ref.service_catalog._region_name = region_name - else: - self.auth_ref = auth_ref - - self.process_token(region_name=region_name) - if new_token_needed: - self.store_auth_ref_into_keyring(keyring_key) - return True - - def _build_keyring_key(self, **kwargs): - """Create a unique key for keyring. - - Used to store and retrieve auth_ref from keyring. - - Return a slash-separated string of values ordered by key name. - - """ - return '/'.join([kwargs[k] or '?' for k in sorted(kwargs)]) - - def get_auth_ref_from_keyring(self, **kwargs): - """Retrieve auth_ref from keyring. - - If auth_ref is found in keyring, (keyring_key, auth_ref) is returned. - Otherwise, (keyring_key, None) is returned. - - :returns: (keyring_key, auth_ref) or (keyring_key, None) - :returns: or (None, None) if use_keyring is not set in the object - - """ - keyring_key = None - auth_ref = None - if self.use_keyring: - keyring_key = self._build_keyring_key(**kwargs) - try: - auth_ref = keyring.get_password("keystoneclient_auth", - keyring_key) - if auth_ref: - auth_ref = pickle.loads(auth_ref) # nosec(cjschaef): see - # bug 1534288 - if auth_ref.will_expire_soon(self.stale_duration): - # token has expired, don't use it - auth_ref = None - except Exception as e: - auth_ref = None - _logger.warning('Unable to retrieve token from keyring %s', e) - return (keyring_key, auth_ref) - - def store_auth_ref_into_keyring(self, keyring_key): - """Store auth_ref into keyring.""" - if self.use_keyring: - try: - keyring.set_password("keystoneclient_auth", - keyring_key, - pickle.dumps(self.auth_ref)) # nosec - # (cjschaef): see bug 1534288 - except Exception as e: - _logger.warning("Failed to store token into keyring %s", e) - - def _process_management_url(self, region_name): - try: - self._management_url = self.auth_ref.service_catalog.url_for( - service_type='identity', - endpoint_type='admin', - region_name=region_name) - except exceptions.EndpointNotFound as e: - _logger.debug("Failed to find endpoint for management url %s", e) - - def process_token(self, region_name=None): - """Extract and process information from the new auth_ref. - - And set the relevant authentication information. - """ - # if we got a response without a service catalog, set the local - # list of tenants for introspection, and leave to client user - # to determine what to do. Otherwise, load up the service catalog - if self.auth_ref.project_scoped: - if not self.auth_ref.tenant_id: - raise exceptions.AuthorizationFailure( - _("Token didn't provide tenant_id")) - self._process_management_url(region_name) - self.project_name = self.auth_ref.tenant_name - self.project_id = self.auth_ref.tenant_id - - if not self.auth_ref.user_id: - raise exceptions.AuthorizationFailure( - _("Token didn't provide user_id")) - - self.user_id = self.auth_ref.user_id - - self.auth_domain_id = self.auth_ref.domain_id - self.auth_tenant_id = self.auth_ref.tenant_id - self.auth_user_id = self.auth_ref.user_id - - @property - def management_url(self): - return self._endpoint or self._management_url - - @management_url.setter - def management_url(self, value): - # NOTE(jamielennox): it's debatable here whether we should set - # _endpoint or _management_url. As historically management_url was set - # permanently setting _endpoint would better match that behaviour. - self._endpoint = value - - @positional(enforcement=positional.WARN) - def get_raw_token_from_identity_service(self, auth_url, username=None, - password=None, tenant_name=None, - tenant_id=None, token=None, - user_id=None, user_domain_id=None, - user_domain_name=None, - domain_id=None, domain_name=None, - project_id=None, project_name=None, - project_domain_id=None, - project_domain_name=None, - trust_id=None): - """Authenticate against the Identity API and get a token. - - Not implemented here because auth protocols should be API - version-specific. - - Expected to authenticate or validate an existing authentication - reference already associated with the client. Invoking this call - *always* makes a call to the Identity service. - - :returns: (``resp``, ``body``) - - """ - raise NotImplementedError - - def serialize(self, entity): - return jsonutils.dumps(entity) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def request(self, *args, **kwargs): - """Send an http request with the specified characteristics. - - Wrapper around requests.request to handle tasks such as - setting headers, JSON encoding/decoding, and error handling. - - .. warning:: - - *DEPRECATED*: This function is no longer used. It was designed to - be used only by the managers and the managers now receive an - adapter so this function is no longer on the standard request path. - This may be removed in the 2.0.0 release. - """ - return self._request(*args, **kwargs) - - def _request(self, *args, **kwargs): - kwargs.setdefault('authenticated', False) - return self._adapter.request(*args, **kwargs) - - def _cs_request(self, url, method, management=True, **kwargs): - """Make an authenticated request to keystone endpoint. - - Request are made to keystone endpoint by concatenating - self.management_url and url and passing in method and - any associated kwargs. - """ - if not management: - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - endpoint_filter.setdefault('interface', 'public') - - kwargs.setdefault('authenticated', None) - return self._request(url, method, **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def get(self, url, **kwargs): - """Perform an authenticated GET request. - - This calls :py:meth:`.request()` with ``method`` set to ``GET`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'GET', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def head(self, url, **kwargs): - """Perform an authenticated HEAD request. - - This calls :py:meth:`.request()` with ``method`` set to ``HEAD`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'HEAD', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def post(self, url, **kwargs): - """Perform an authenticate POST request. - - This calls :py:meth:`.request()` with ``method`` set to ``POST`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'POST', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def put(self, url, **kwargs): - """Perform an authenticate PUT request. - - This calls :py:meth:`.request()` with ``method`` set to ``PUT`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'PUT', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def patch(self, url, **kwargs): - """Perform an authenticate PATCH request. - - This calls :py:meth:`.request()` with ``method`` set to ``PATCH`` and - an authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'PATCH', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def delete(self, url, **kwargs): - """Perform an authenticate DELETE request. - - This calls :py:meth:`.request()` with ``method`` set to ``DELETE`` and - an authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'DELETE', **kwargs) - - deprecated_session_variables = {'original_ip': None, - 'cert': None, - 'timeout': None, - 'verify_cert': 'verify'} - - deprecated_adapter_variables = {'region_name': None} - - def __getattr__(self, name): - """Fetch deprecated session variables.""" - try: - var_name = self.deprecated_session_variables[name] - except KeyError: # nosec(cjschaef): try adapter variable or raise - # an AttributeError - pass - else: - warnings.warn( - 'The %s session variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return getattr(self.session, var_name or name) - - try: - var_name = self.deprecated_adapter_variables[name] - except KeyError: # nosec(cjschaef): raise an AttributeError - pass - else: - warnings.warn( - 'The %s adapter variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return getattr(self._adapter, var_name or name) - - raise AttributeError(_("Unknown Attribute: %s") % name) - - def __setattr__(self, name, val): - """Assign value to deprecated seesion variables.""" - try: - var_name = self.deprecated_session_variables[name] - except KeyError: # nosec(cjschaef): try adapter variable or call - # parent class's __setattr__ - pass - else: - warnings.warn( - 'The %s session variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return setattr(self.session, var_name or name) - - try: - var_name = self.deprecated_adapter_variables[name] - except KeyError: # nosec(cjschaef): call parent class's __setattr__ - pass - else: - warnings.warn( - 'The %s adapter variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return setattr(self._adapter, var_name or name) - - super(HTTPClient, self).__setattr__(name, val) diff --git a/keystoneclient/i18n.py b/keystoneclient/i18n.py deleted file mode 100644 index f3726d19..00000000 --- a/keystoneclient/i18n.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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. - -"""oslo.i18n integration module. - -See https://docs.openstack.org/oslo.i18n/latest/user/index.html . - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='keystoneclient') - -# The primary translation function using the well-known name "_" -_ = _translators.primary diff --git a/keystoneclient/service_catalog.py b/keystoneclient/service_catalog.py deleted file mode 100644 index 45d7d0a6..00000000 --- a/keystoneclient/service_catalog.py +++ /dev/null @@ -1,432 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011, Piston Cloud Computing, Inc. -# Copyright 2011 Nebula, Inc. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import abc -import warnings - -from positional import positional -import six - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -@six.add_metaclass(abc.ABCMeta) -class ServiceCatalog(object): - """Helper methods for dealing with a Keystone Service Catalog. - - .. warning:: - - Setting region_name is deprecated in favor of passing the region name - as a parameter to calls made to the service catalog as of the 1.7.0 - release and may be removed in the 2.0.0 release. - - """ - - @classmethod - def factory(cls, resource_dict, token=None, region_name=None): - """Create ServiceCatalog object given an auth token. - - .. warning:: - - Setting region_name is deprecated in favor of passing the region - name as a parameter to calls made to the service catalog as of the - 1.7.0 release and may be removed in the 2.0.0 release. - - """ - if ServiceCatalogV3.is_valid(resource_dict): - return ServiceCatalogV3(token, resource_dict, region_name) - elif ServiceCatalogV2.is_valid(resource_dict): - return ServiceCatalogV2(resource_dict, region_name) - else: - raise NotImplementedError(_('Unrecognized auth response')) - - def __init__(self, region_name=None): - if region_name: - warnings.warn( - 'Setting region_name on the service catalog is deprecated in ' - 'favor of passing the region name as a parameter to calls ' - 'made to the service catalog as of the 1.7.0 release and may ' - 'be removed in the 2.0.0 release.', - DeprecationWarning) - - self._region_name = region_name - - @property - def region_name(self): - """Region name. - - .. warning:: - - region_name is deprecated in favor of passing the region name as a - parameter to calls made to the service catalog as of the 1.7.0 - release and may be removed in the 2.0.0 release. - - """ - warnings.warn( - 'region_name is deprecated in favor of passing the region name as ' - 'a parameter to calls made to the service catalog as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release.', - DeprecationWarning) - return self._region_name - - def _get_endpoint_region(self, endpoint): - return endpoint.get('region_id') or endpoint.get('region') - - @abc.abstractmethod - def get_token(self): - """Fetch token details from service catalog. - - Returns a dictionary containing the following:: - - - `id`: Token's ID - - `expires`: Token's expiration - - `user_id`: Authenticated user's ID - - `tenant_id`: Authorized project's ID - - `domain_id`: Authorized domain's ID - - """ - raise NotImplementedError() # pragma: no cover - - @abc.abstractmethod - def _is_endpoint_type_match(self, endpoint, endpoint_type): - """Helper function to normalize endpoint matching across v2 and v3. - - :returns: True if the provided endpoint matches the required - endpoint_type otherwise False. - """ - pass # pragma: no cover - - @abc.abstractmethod - def _normalize_endpoint_type(self, endpoint_type): - """Handle differences in the way v2 and v3 catalogs specify endpoint. - - Both v2 and v3 must be able to handle the endpoint style of the other. - For example v2 must be able to handle a 'public' endpoint_type and - v3 must be able to handle a 'publicURL' endpoint_type. - - :returns: the endpoint string in the format appropriate for this - service catalog. - """ - pass # pragma: no cover - - def get_endpoints(self, service_type=None, endpoint_type=None, - region_name=None, service_name=None): - """Fetch and filter endpoints for the specified service(s). - - Returns endpoints for the specified service (or all) containing - the specified type (or all) and region (or all) and service name. - - If there is no name in the service catalog the service_name check will - be skipped. This allows compatibility with services that existed - before the name was available in the catalog. - """ - endpoint_type = self._normalize_endpoint_type(endpoint_type) - region_name = region_name or self._region_name - - sc = {} - - for service in (self.get_data() or []): - try: - st = service['type'] - except KeyError: - continue - - if service_type and service_type != st: - continue - - # NOTE(jamielennox): service_name is different. It is not available - # in API < v3.3. If it is in the catalog then we enforce it, if it - # is not then we don't because the name could be correct we just - # don't have that information to check against. - if service_name: - try: - sn = service['name'] - except KeyError: # nosec(cjschaef) - # assume that we're in v3.0-v3.2 and don't have the name in - # the catalog. Skip the check. - pass - else: - if service_name != sn: - continue - - endpoints = sc.setdefault(st, []) - - for endpoint in service.get('endpoints', []): - if (endpoint_type and not - self._is_endpoint_type_match(endpoint, endpoint_type)): - continue - if (region_name and - region_name != self._get_endpoint_region(endpoint)): - continue - endpoints.append(endpoint) - - return sc - - def _get_service_endpoints(self, attr, filter_value, service_type, - endpoint_type, region_name, service_name): - """Fetch the endpoints of a particular service_type. - - Endpoints returned are also filtered based on the attr and - filter_value provided. - """ - sc_endpoints = self.get_endpoints(service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - try: - endpoints = sc_endpoints[service_type] - except KeyError: - return - - if attr and not filter_value: - warnings.warn( - 'Providing attr without filter_value to get_urls() is ' - 'deprecated as of the 1.7.0 release and may be removed in the ' - '2.0.0 release. Either both should be provided or neither ' - 'should be provided.') - - if filter_value: - return [endpoint for endpoint in endpoints - if endpoint.get(attr) == filter_value] - - return endpoints - - @abc.abstractmethod - @positional(enforcement=positional.WARN) - def get_urls(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL', - region_name=None, service_name=None): - """Fetch endpoint urls from the service catalog. - - Fetch the endpoints from the service catalog for a particular - endpoint attribute. If no attribute is given, return the first - endpoint of the specified type. - - :param string attr: Endpoint attribute name. - :param string filter_value: Endpoint attribute value. - :param string service_type: Service type of the endpoint. - :param string endpoint_type: Type of endpoint. - Possible values: public or publicURL, - internal or internalURL, admin or - adminURL - :param string region_name: Region of the endpoint. - :param string service_name: The assigned name of the service. - - :returns: tuple of urls or None (if no match found) - """ - raise NotImplementedError() # pragma: no cover - - @positional(3, enforcement=positional.WARN) - def url_for(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL', - region_name=None, service_name=None): - """Fetch an endpoint from the service catalog. - - Fetch the specified endpoint from the service catalog for - a particular endpoint attribute. If no attribute is given, return - the first endpoint of the specified type. - - Valid endpoint types: `public` or `publicURL`, - `internal` or `internalURL`, - `admin` or 'adminURL` - - :param string attr: Endpoint attribute name. - :param string filter_value: Endpoint attribute value. - :param string service_type: Service type of the endpoint. - :param string endpoint_type: Type of endpoint. - :param string region_name: Region of the endpoint. - :param string service_name: The assigned name of the service. - - """ - if not self.get_data(): - raise exceptions.EmptyCatalog(_('The service catalog is empty.')) - - urls = self.get_urls(attr=attr, - filter_value=filter_value, - service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - try: - return urls[0] - except Exception: - if service_name and region_name: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service named %(service_name)s in %(region_name)s ' - 'region not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type, - 'service_name': service_name, - 'region_name': region_name}) - elif service_name: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service named %(service_name)s not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type, - 'service_name': service_name}) - elif region_name: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service in %(region_name)s region not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type, - 'region_name': region_name}) - else: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type}) - - raise exceptions.EndpointNotFound(msg) - - @abc.abstractmethod - def get_data(self): - """Get the raw catalog structure. - - Get the version dependent catalog structure as it is presented within - the resource. - - :returns: list containing raw catalog data entries or None - """ - raise NotImplementedError() # pragma: no cover - - -class ServiceCatalogV2(ServiceCatalog): - """An object for encapsulating the v2 service catalog. - - The object is created using raw v2 auth token from Keystone. - """ - - def __init__(self, resource_dict, region_name=None): - self.catalog = resource_dict - super(ServiceCatalogV2, self).__init__(region_name=region_name) - - @classmethod - def is_valid(cls, resource_dict): - # This class is also used for reading token info of an unscoped token. - # Unscoped token does not have 'serviceCatalog' in V2, checking this - # will not work. Use 'token' attribute instead. - return 'token' in resource_dict - - def _normalize_endpoint_type(self, endpoint_type): - if endpoint_type and 'URL' not in endpoint_type: - endpoint_type += 'URL' - - return endpoint_type - - def _is_endpoint_type_match(self, endpoint, endpoint_type): - return endpoint_type in endpoint - - def get_data(self): - return self.catalog.get('serviceCatalog') - - def get_token(self): - token = {'id': self.catalog['token']['id'], - 'expires': self.catalog['token']['expires']} - try: - token['user_id'] = self.catalog['user']['id'] - token['tenant_id'] = self.catalog['token']['tenant']['id'] - except KeyError: # nosec(cjschaef) - # just leave the tenant and user out if it doesn't exist - pass - return token - - @positional(enforcement=positional.WARN) - def get_urls(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL', - region_name=None, service_name=None): - endpoint_type = self._normalize_endpoint_type(endpoint_type) - endpoints = self._get_service_endpoints(attr=attr, - filter_value=filter_value, - service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - if endpoints: - return tuple([endpoint[endpoint_type] for endpoint in endpoints]) - else: - return None - - -class ServiceCatalogV3(ServiceCatalog): - """An object for encapsulating the v3 service catalog. - - The object is created using raw v3 auth token from Keystone. - """ - - def __init__(self, token, resource_dict, region_name=None): - super(ServiceCatalogV3, self).__init__(region_name=region_name) - self._auth_token = token - self.catalog = resource_dict - - @classmethod - def is_valid(cls, resource_dict): - # This class is also used for reading token info of an unscoped token. - # Unscoped token does not have 'catalog', checking this - # will not work. Use 'methods' attribute instead. - return 'methods' in resource_dict - - def _normalize_endpoint_type(self, endpoint_type): - if endpoint_type: - endpoint_type = endpoint_type.rstrip('URL') - - return endpoint_type - - def _is_endpoint_type_match(self, endpoint, endpoint_type): - try: - return endpoint_type == endpoint['interface'] - except KeyError: - return False - - def get_data(self): - return self.catalog.get('catalog') - - def get_token(self): - token = {'id': self._auth_token, - 'expires': self.catalog['expires_at']} - try: - token['user_id'] = self.catalog['user']['id'] - domain = self.catalog.get('domain') - if domain: - token['domain_id'] = domain['id'] - project = self.catalog.get('project') - if project: - token['tenant_id'] = project['id'] - except KeyError: # nosec(cjschaef) - # just leave the domain, project and user out if it doesn't exist - pass - return token - - @positional(enforcement=positional.WARN) - def get_urls(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='public', - region_name=None, service_name=None): - endpoints = self._get_service_endpoints(attr=attr, - filter_value=filter_value, - service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - if endpoints: - return tuple([endpoint['url'] for endpoint in endpoints]) - else: - return None diff --git a/keystoneclient/session.py b/keystoneclient/session.py deleted file mode 100644 index 9faedacd..00000000 --- a/keystoneclient/session.py +++ /dev/null @@ -1,1020 +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. - -import argparse -import functools -import hashlib -import logging -import os -import socket -import time -import warnings - -from debtcollector import removals -from oslo_config import cfg -from oslo_serialization import jsonutils -from oslo_utils import encodeutils -from oslo_utils import importutils -from oslo_utils import strutils -from positional import positional -import requests -import six -from six.moves import urllib - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - -osprofiler_web = importutils.try_import("osprofiler.web") - -USER_AGENT = 'python-keystoneclient' - -# NOTE(jamielennox): Clients will likely want to print more than json. Please -# propose a patch if you have a content type you think is reasonable to print -# here and we'll add it to the list as required. -_LOG_CONTENT_TYPES = set(['application/json']) - -_logger = logging.getLogger(__name__) - - -def _positive_non_zero_float(argument_value): - if argument_value is None: - return None - try: - value = float(argument_value) - except ValueError: - msg = _("%s must be a float") % argument_value - raise argparse.ArgumentTypeError(msg) - if value <= 0: - msg = _("%s must be greater than 0") % argument_value - raise argparse.ArgumentTypeError(msg) - return value - - -def request(url, method='GET', **kwargs): - return Session().request(url, method=method, **kwargs) - - -def _remove_service_catalog(body): - try: - data = jsonutils.loads(body) - - # V3 token - if 'token' in data and 'catalog' in data['token']: - data['token']['catalog'] = '' - return jsonutils.dumps(data) - - # V2 token - if 'serviceCatalog' in data['access']: - data['access']['serviceCatalog'] = '' - return jsonutils.dumps(data) - - except Exception: # nosec(cjschaef): multiple exceptions can be raised - # Don't fail trying to clean up the request body. - pass - return body - - -class Session(object): - """Maintains client communication state and common functionality. - - As much as possible the parameters to this class reflect and are passed - directly to the requests library. - - :param auth: An authentication plugin to authenticate the session with. - (optional, defaults to None) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - :param requests.Session session: A requests session object that can be used - for issuing requests. (optional) - :param string original_ip: The original IP of the requesting user which - will be sent to identity service in a - 'Forwarded' header. (optional) - :param verify: The verification arguments to pass to requests. These are of - the same form as requests expects, so True or False to - verify (or not) against system certificates or a path to a - bundle or CA certs to check against or None for requests to - attempt to locate and use certificates. (optional, defaults - to True) - :param cert: A client certificate to pass to requests. These are of the - same form as requests expects. Either a single filename - containing both the certificate and key or a tuple containing - the path to the certificate then a path to the key. (optional) - :param float timeout: A timeout to pass to requests. This should be a - numerical value indicating some amount (or fraction) - of seconds or 0 for no timeout. (optional, defaults - to 0) - :param string user_agent: A User-Agent header string to use for the - request. If not provided a default is used. - (optional, defaults to 'python-keystoneclient') - :param int/bool redirect: Controls the maximum number of redirections that - can be followed by a request. Either an integer - for a specific count or True/False for - forever/never. (optional, default to 30) - """ - - user_agent = None - - _REDIRECT_STATUSES = (301, 302, 303, 305, 307) - - REDIRECT_STATUSES = _REDIRECT_STATUSES - """This property is deprecated as of the 1.7.0 release and may be removed - in the 2.0.0 release.""" - - _DEFAULT_REDIRECT_LIMIT = 30 - - DEFAULT_REDIRECT_LIMIT = _DEFAULT_REDIRECT_LIMIT - """This property is deprecated as of the 1.7.0 release and may be removed - in the 2.0.0 release.""" - - @positional(2, enforcement=positional.WARN) - def __init__(self, auth=None, session=None, original_ip=None, verify=True, - cert=None, timeout=None, user_agent=None, - redirect=_DEFAULT_REDIRECT_LIMIT): - warnings.warn( - 'keystoneclient.session.Session is deprecated as of the 2.1.0 ' - 'release in favor of keystoneauth1.session.Session. It will be ' - 'removed in future releases.', - DeprecationWarning) - - if not session: - session = requests.Session() - # Use TCPKeepAliveAdapter to fix bug 1323862 - for scheme in list(session.adapters): - session.mount(scheme, TCPKeepAliveAdapter()) - - self.auth = auth - self.session = session - self.original_ip = original_ip - self.verify = verify - self.cert = cert - self.timeout = None - self.redirect = redirect - - if timeout is not None: - self.timeout = float(timeout) - - # don't override the class variable if none provided - if user_agent is not None: - self.user_agent = user_agent - - @staticmethod - def _process_header(header): - """Redact the secure headers to be logged.""" - secure_headers = ('authorization', 'x-auth-token', - 'x-subject-token', 'x-service-token') - if header[0].lower() in secure_headers: - token_hasher = hashlib.sha1() - token_hasher.update(header[1].encode('utf-8')) - token_hash = token_hasher.hexdigest() - return (header[0], '{SHA1}%s' % token_hash) - return header - - @positional() - def _http_log_request(self, url, method=None, data=None, - headers=None, logger=_logger): - if not logger.isEnabledFor(logging.DEBUG): - # NOTE(morganfainberg): This whole debug section is expensive, - # there is no need to do the work if we're not going to emit a - # debug log. - return - - string_parts = ['REQ: curl -g -i'] - - # NOTE(jamielennox): None means let requests do its default validation - # so we need to actually check that this is False. - if self.verify is False: - string_parts.append('--insecure') - elif isinstance(self.verify, six.string_types): - string_parts.append('--cacert "%s"' % self.verify) - - if method: - string_parts.extend(['-X', method]) - - string_parts.append(url) - - if headers: - for header in headers.items(): - string_parts.append('-H "%s: %s"' - % self._process_header(header)) - - if data: - if isinstance(data, six.binary_type): - try: - data = data.decode("ascii") - except UnicodeDecodeError: - data = "" - string_parts.append("-d '%s'" % data) - try: - logger.debug(' '.join(string_parts)) - except UnicodeDecodeError: - logger.debug("Replaced characters that could not be decoded" - " in log output, original caused UnicodeDecodeError") - string_parts = [ - encodeutils.safe_decode( - part, errors='replace') for part in string_parts] - logger.debug(' '.join(string_parts)) - - def _http_log_response(self, response, logger): - if not logger.isEnabledFor(logging.DEBUG): - return - - # NOTE(samueldmq): If the response does not provide enough info about - # the content type to decide whether it is useful and safe to log it - # or not, just do not log the body. Trying to# read the response body - # anyways may result on reading a long stream of bytes and getting an - # unexpected MemoryError. See bug 1616105 for further details. - content_type = response.headers.get('content-type', None) - - # NOTE(lamt): Per [1], the Content-Type header can be of the form - # Content-Type := type "/" subtype *[";" parameter] - # [1] https://www.w3.org/Protocols/rfc1341/4_Content-Type.html - for log_type in _LOG_CONTENT_TYPES: - if content_type is not None and content_type.startswith(log_type): - text = _remove_service_catalog(response.text) - break - else: - text = ('Omitted, Content-Type is set to %s. Only ' - '%s responses have their bodies logged.') - text = text % (content_type, ', '.join(_LOG_CONTENT_TYPES)) - - string_parts = [ - 'RESP:', - '[%s]' % response.status_code - ] - for header in response.headers.items(): - string_parts.append('%s: %s' % self._process_header(header)) - string_parts.append('\nRESP BODY: %s\n' % strutils.mask_password(text)) - - logger.debug(' '.join(string_parts)) - - # NOTE(artmr): parameter 'original_ip' value is never used - @positional(enforcement=positional.WARN) - def request(self, url, method, json=None, original_ip=None, - user_agent=None, redirect=None, authenticated=None, - endpoint_filter=None, auth=None, requests_auth=None, - raise_exc=True, allow_reauth=True, log=True, - endpoint_override=None, connect_retries=0, logger=_logger, - **kwargs): - """Send an HTTP request with the specified characteristics. - - Wrapper around `requests.Session.request` to handle tasks such as - setting headers, JSON encoding/decoding, and error handling. - - Arguments that are not handled are passed through to the requests - library. - - :param string url: Path or fully qualified URL of HTTP request. If only - a path is provided then endpoint_filter must also be - provided such that the base URL can be determined. - If a fully qualified URL is provided then - endpoint_filter will be ignored. - :param string method: The http method to use. (e.g. 'GET', 'POST') - :param string original_ip: Mark this request as forwarded for this ip. - (optional) - :param dict headers: Headers to be included in the request. (optional) - :param json: Some data to be represented as JSON. (optional) - :param string user_agent: A user_agent to use for the request. If - present will override one present in headers. - (optional) - :param int/bool redirect: the maximum number of redirections that - can be followed by a request. Either an - integer for a specific count or True/False - for forever/never. (optional) - :param int connect_retries: the maximum number of retries that should - be attempted for connection errors. - (optional, defaults to 0 - never retry). - :param bool authenticated: True if a token should be attached to this - request, False if not or None for attach if - an auth_plugin is available. - (optional, defaults to None) - :param dict endpoint_filter: Data to be provided to an auth plugin with - which it should be able to determine an - endpoint to use for this request. If not - provided then URL is expected to be a - fully qualified URL. (optional) - :param str endpoint_override: The URL to use instead of looking up the - endpoint in the auth plugin. This will be - ignored if a fully qualified URL is - provided but take priority over an - endpoint_filter. (optional) - :param auth: The auth plugin to use when authenticating this request. - This will override the plugin that is attached to the - session (if any). (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - :param requests_auth: A requests library auth plugin that cannot be - passed via kwarg because the `auth` kwarg - collides with our own auth plugins. (optional) - :type requests_auth: :py:class:`requests.auth.AuthBase` - :param bool raise_exc: If True then raise an appropriate exception for - failed HTTP requests. If False then return the - request object. (optional, default True) - :param bool allow_reauth: Allow fetching a new token and retrying the - request on receiving a 401 Unauthorized - response. (optional, default True) - :param bool log: If True then log the request and response data to the - debug log. (optional, default True) - :param logger: The logger object to use to log request and responses. - If not provided the keystoneclient.session default - logger will be used. - :type logger: logging.Logger - :param kwargs: any other parameter that can be passed to - requests.Session.request (such as `headers`). Except: - 'data' will be overwritten by the data in 'json' param. - 'allow_redirects' is ignored as redirects are handled - by the session. - - :raises keystoneclient.exceptions.ClientException: For connection - failure, or to indicate an error response code. - - :returns: The response to the request. - """ - headers = kwargs.setdefault('headers', dict()) - - if authenticated is None: - authenticated = bool(auth or self.auth) - - if authenticated: - auth_headers = self.get_auth_headers(auth) - - if auth_headers is None: - msg = _('No valid authentication is available') - raise exceptions.AuthorizationFailure(msg) - - headers.update(auth_headers) - - if osprofiler_web: - headers.update(osprofiler_web.get_trace_id_headers()) - - # if we are passed a fully qualified URL and an endpoint_filter we - # should ignore the filter. This will make it easier for clients who - # want to overrule the default endpoint_filter data added to all client - # requests. We check fully qualified here by the presence of a host. - if not urllib.parse.urlparse(url).netloc: - base_url = None - - if endpoint_override: - base_url = endpoint_override - elif endpoint_filter: - base_url = self.get_endpoint(auth, **endpoint_filter) - - if not base_url: - service_type = (endpoint_filter or {}).get('service_type', - 'unknown') - msg = _('Endpoint for %s service') % service_type - raise exceptions.EndpointNotFound(msg) - - url = '%s/%s' % (base_url.rstrip('/'), url.lstrip('/')) - - if self.cert: - kwargs.setdefault('cert', self.cert) - - if self.timeout is not None: - kwargs.setdefault('timeout', self.timeout) - - if user_agent: - headers['User-Agent'] = user_agent - elif self.user_agent: - user_agent = headers.setdefault('User-Agent', self.user_agent) - else: - user_agent = headers.setdefault('User-Agent', USER_AGENT) - - if self.original_ip: - headers.setdefault('Forwarded', - 'for=%s;by=%s' % (self.original_ip, user_agent)) - - if json is not None: - headers['Content-Type'] = 'application/json' - kwargs['data'] = jsonutils.dumps(json) - - kwargs.setdefault('verify', self.verify) - - if requests_auth: - kwargs['auth'] = requests_auth - - if log: - self._http_log_request(url, method=method, - data=kwargs.get('data'), - headers=headers, - logger=logger) - - # Force disable requests redirect handling. We will manage this below. - kwargs['allow_redirects'] = False - - if redirect is None: - redirect = self.redirect - - send = functools.partial(self._send_request, - url, method, redirect, log, logger, - connect_retries) - - try: - connection_params = self.get_auth_connection_params(auth=auth) - except exceptions.MissingAuthPlugin: # nosec(cjschaef) - # NOTE(jamielennox): If we've gotten this far without an auth - # plugin then we should be happy with allowing no additional - # connection params. This will be the typical case for plugins - # anyway. - pass - else: - if connection_params: - kwargs.update(connection_params) - - resp = send(**kwargs) - - # handle getting a 401 Unauthorized response by invalidating the plugin - # and then retrying the request. This is only tried once. - if resp.status_code == 401 and authenticated and allow_reauth: - if self.invalidate(auth): - auth_headers = self.get_auth_headers(auth) - - if auth_headers is not None: - headers.update(auth_headers) - resp = send(**kwargs) - - if raise_exc and resp.status_code >= 400: - logger.debug('Request returned failure status: %s', - resp.status_code) - raise exceptions.from_response(resp, method, url) - - return resp - - def _send_request(self, url, method, redirect, log, logger, - connect_retries, connect_retry_delay=0.5, **kwargs): - # NOTE(jamielennox): We handle redirection manually because the - # requests lib follows some browser patterns where it will redirect - # POSTs as GETs for certain statuses which is not want we want for an - # API. See: https://en.wikipedia.org/wiki/Post/Redirect/Get - - # NOTE(jamielennox): The interaction between retries and redirects are - # handled naively. We will attempt only a maximum number of retries and - # redirects rather than per request limits. Otherwise the extreme case - # could be redirects * retries requests. This will be sufficient in - # most cases and can be fixed properly if there's ever a need. - - try: - try: - resp = self.session.request(method, url, **kwargs) - except requests.exceptions.SSLError as e: - msg = _('SSL exception connecting to %(url)s: ' - '%(error)s') % {'url': url, 'error': e} - raise exceptions.SSLError(msg) - except requests.exceptions.Timeout: - msg = _('Request to %s timed out') % url - raise exceptions.RequestTimeout(msg) - except requests.exceptions.ConnectionError: - msg = _('Unable to establish connection to %s') % url - raise exceptions.ConnectionRefused(msg) - except (exceptions.RequestTimeout, exceptions.ConnectionRefused) as e: - if connect_retries <= 0: - raise - - logger.info('Failure: %(e)s. Retrying in %(delay).1fs.', - {'e': e, 'delay': connect_retry_delay}) - time.sleep(connect_retry_delay) - - return self._send_request( - url, method, redirect, log, logger, - connect_retries=connect_retries - 1, - connect_retry_delay=connect_retry_delay * 2, - **kwargs) - - if log: - self._http_log_response(resp, logger) - - if resp.status_code in self._REDIRECT_STATUSES: - # be careful here in python True == 1 and False == 0 - if isinstance(redirect, bool): - redirect_allowed = redirect - else: - redirect -= 1 - redirect_allowed = redirect >= 0 - - if not redirect_allowed: - return resp - - try: - location = resp.headers['location'] - except KeyError: - logger.warning("Failed to redirect request to %s as new " - "location was not provided.", resp.url) - else: - # NOTE(jamielennox): We don't pass through connect_retry_delay. - # This request actually worked so we can reset the delay count. - new_resp = self._send_request( - location, method, redirect, log, logger, - connect_retries=connect_retries, - **kwargs) - - if not isinstance(new_resp.history, list): - new_resp.history = list(new_resp.history) - new_resp.history.insert(0, resp) - resp = new_resp - - return resp - - def head(self, url, **kwargs): - """Perform a HEAD request. - - This calls :py:meth:`.request()` with ``method`` set to ``HEAD``. - - """ - return self.request(url, 'HEAD', **kwargs) - - def get(self, url, **kwargs): - """Perform a GET request. - - This calls :py:meth:`.request()` with ``method`` set to ``GET``. - - """ - return self.request(url, 'GET', **kwargs) - - def post(self, url, **kwargs): - """Perform a POST request. - - This calls :py:meth:`.request()` with ``method`` set to ``POST``. - - """ - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - """Perform a PUT request. - - This calls :py:meth:`.request()` with ``method`` set to ``PUT``. - - """ - return self.request(url, 'PUT', **kwargs) - - def delete(self, url, **kwargs): - """Perform a DELETE request. - - This calls :py:meth:`.request()` with ``method`` set to ``DELETE``. - - """ - return self.request(url, 'DELETE', **kwargs) - - def patch(self, url, **kwargs): - """Perform a PATCH request. - - This calls :py:meth:`.request()` with ``method`` set to ``PATCH``. - - """ - return self.request(url, 'PATCH', **kwargs) - - @classmethod - def construct(cls, kwargs): - """Handle constructing a session from both old and new arguments. - - Support constructing a session from the old - :py:class:`~keystoneclient.httpclient.HTTPClient` args as well as the - new request-style arguments. - - .. warning:: - - *DEPRECATED as of 1.7.0*: This function is purely for bridging the - gap between older client arguments and the session arguments that - they relate to. It is not intended to be used as a generic Session - Factory. This function may be removed in the 2.0.0 release. - - This function purposefully modifies the input kwargs dictionary so that - the remaining kwargs dict can be reused and passed on to other - functions without session arguments. - - """ - warnings.warn( - 'Session.construct() is deprecated as of the 1.7.0 release in ' - 'favor of using session constructor and may be removed in the ' - '2.0.0 release.', DeprecationWarning) - return cls._construct(kwargs) - - @classmethod - def _construct(cls, kwargs): - params = {} - - for attr in ('verify', 'cacert', 'cert', 'key', 'insecure', - 'timeout', 'session', 'original_ip', 'user_agent'): - try: - params[attr] = kwargs.pop(attr) - except KeyError: # nosec(cjschaef): we are brute force - # identifying possible attributes for kwargs - pass - - return cls._make(**params) - - @classmethod - def _make(cls, insecure=False, verify=None, cacert=None, cert=None, - key=None, **kwargs): - """Create a session with individual certificate parameters. - - Some parameters used to create a session don't lend themselves to be - loaded from config/CLI etc. Create a session by converting those - parameters into session __init__ parameters. - """ - if verify is None: - if insecure: - verify = False - else: - verify = cacert or True - - if cert and key: - warnings.warn( - 'Passing cert and key together is deprecated as of the 1.7.0 ' - 'release in favor of the requests library form of having the ' - 'cert and key as a tuple and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - cert = (cert, key) - - return cls(verify=verify, cert=cert, **kwargs) - - def _auth_required(self, auth, msg): - if not auth: - auth = self.auth - - if not auth: - raise exceptions.MissingAuthPlugin(msg) - - return auth - - def get_auth_headers(self, auth=None, **kwargs): - """Return auth headers as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - :returns: Authentication headers or None for failure. - :rtype: dict - """ - msg = _('An auth plugin is required to fetch a token') - auth = self._auth_required(auth, msg) - return auth.get_headers(self, **kwargs) - - @removals.remove(message='Use get_auth_headers instead.', version='1.7.0', - removal_version='2.0.0') - def get_token(self, auth=None): - """Return a token as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - .. warning:: - - This method is deprecated as of the 1.7.0 release in favor of - :meth:`get_auth_headers` and may be removed in the 2.0.0 release. - This method assumes that the only header that is used to - authenticate a message is 'X-Auth-Token' which may not be correct. - - :returns: A valid token. - :rtype: string - """ - return (self.get_auth_headers(auth) or {}).get('X-Auth-Token') - - def get_endpoint(self, auth=None, **kwargs): - """Get an endpoint as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin on - the session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - :returns: An endpoint if available or None. - :rtype: string - """ - msg = _('An auth plugin is required to determine endpoint URL') - auth = self._auth_required(auth, msg) - return auth.get_endpoint(self, **kwargs) - - def get_auth_connection_params(self, auth=None, **kwargs): - """Return auth connection params as provided by the auth plugin. - - An auth plugin may specify connection parameters to the request like - providing a client certificate for communication. - - We restrict the values that may be returned from this function to - prevent an auth plugin overriding values unrelated to connection - parameters. The values that are currently accepted are: - - - `cert`: a path to a client certificate, or tuple of client - certificate and key pair that are used with this request. - - `verify`: a boolean value to indicate verifying SSL certificates - against the system CAs or a path to a CA file to verify with. - - These values are passed to the requests library and further information - on accepted values may be found there. - - :param auth: The auth plugin to use for tokens. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - :raises keystoneclient.exceptions.UnsupportedParameters: if the plugin - returns a parameter that is not supported by this session. - - :returns: Authentication headers or None for failure. - :rtype: dict - """ - msg = _('An auth plugin is required to fetch connection params') - auth = self._auth_required(auth, msg) - params = auth.get_connection_params(self, **kwargs) - - # NOTE(jamielennox): There needs to be some consensus on what - # parameters are allowed to be modified by the auth plugin here. - # Ideally I think it would be only the send() parts of the request - # flow. For now lets just allow certain elements. - params_copy = params.copy() - - for arg in ('cert', 'verify'): - try: - kwargs[arg] = params_copy.pop(arg) - except KeyError: # nosec(cjschaef): we are brute force - # identifying and removing values in params_copy - pass - - if params_copy: - raise exceptions.UnsupportedParameters(list(params_copy)) - - return params - - def invalidate(self, auth=None): - """Invalidate an authentication plugin. - - :param auth: The auth plugin to invalidate. Overrides the plugin on the - session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - """ - msg = _('An auth plugin is required to validate') - auth = self._auth_required(auth, msg) - return auth.invalidate() - - def get_user_id(self, auth=None): - """Return the authenticated user_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns string: Current user_id or None if not supported by plugin. - """ - msg = _('An auth plugin is required to get user_id') - auth = self._auth_required(auth, msg) - return auth.get_user_id(self) - - def get_project_id(self, auth=None): - """Return the authenticated project_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns string: Current project_id or None if not supported by plugin. - """ - msg = _('An auth plugin is required to get project_id') - auth = self._auth_required(auth, msg) - return auth.get_project_id(self) - - @positional.classmethod() - def get_conf_options(cls, deprecated_opts=None): - """Get oslo_config options that are needed for a :py:class:`.Session`. - - These may be useful without being registered for config file generation - or to manipulate the options before registering them yourself. - - The options that are set are: - :cafile: The certificate authority filename. - :certfile: The client certificate file to present. - :keyfile: The key for the client certificate. - :insecure: Whether to ignore SSL verification. - :timeout: The max time to wait for HTTP connections. - - :param dict deprecated_opts: Deprecated options that should be included - in the definition of new options. This should be a dict from the - name of the new option to a list of oslo.DeprecatedOpts that - correspond to the new option. (optional) - - For example, to support the ``ca_file`` option pointing to the new - ``cafile`` option name:: - - old_opt = oslo_cfg.DeprecatedOpt('ca_file', 'old_group') - deprecated_opts={'cafile': [old_opt]} - - :returns: A list of oslo_config options. - """ - if deprecated_opts is None: - deprecated_opts = {} - - return [cfg.StrOpt('cafile', - deprecated_opts=deprecated_opts.get('cafile'), - help='PEM encoded Certificate Authority to use ' - 'when verifying HTTPs connections.'), - cfg.StrOpt('certfile', - deprecated_opts=deprecated_opts.get('certfile'), - help='PEM encoded client certificate cert file'), - cfg.StrOpt('keyfile', - deprecated_opts=deprecated_opts.get('keyfile'), - help='PEM encoded client certificate key file'), - cfg.BoolOpt('insecure', - default=False, - deprecated_opts=deprecated_opts.get('insecure'), - help='Verify HTTPS connections.'), - cfg.IntOpt('timeout', - deprecated_opts=deprecated_opts.get('timeout'), - help='Timeout value for http requests'), - ] - - @positional.classmethod() - def register_conf_options(cls, conf, group, deprecated_opts=None): - """Register the oslo_config options that are needed for a session. - - The options that are set are: - :cafile: The certificate authority filename. - :certfile: The client certificate file to present. - :keyfile: The key for the client certificate. - :insecure: Whether to ignore SSL verification. - :timeout: The max time to wait for HTTP connections. - - :param oslo_config.Cfg conf: config object to register with. - :param string group: The ini group to register options in. - :param dict deprecated_opts: Deprecated options that should be included - in the definition of new options. This should be a dict from the - name of the new option to a list of oslo.DeprecatedOpts that - correspond to the new option. (optional) - - For example, to support the ``ca_file`` option pointing to the new - ``cafile`` option name:: - - old_opt = oslo_cfg.DeprecatedOpt('ca_file', 'old_group') - deprecated_opts={'cafile': [old_opt]} - - :returns: The list of options that was registered. - """ - opts = cls.get_conf_options(deprecated_opts=deprecated_opts) - conf.register_group(cfg.OptGroup(group)) - conf.register_opts(opts, group=group) - return opts - - @classmethod - def load_from_conf_options(cls, conf, group, **kwargs): - """Create a session object from an oslo_config object. - - The options must have been previously registered with - register_conf_options. - - :param oslo_config.Cfg conf: config object to register with. - :param string group: The ini group to register options in. - :param dict kwargs: Additional parameters to pass to session - construction. - :returns: A new session object. - :rtype: :py:class:`.Session` - """ - c = conf[group] - - kwargs['insecure'] = c.insecure - kwargs['cacert'] = c.cafile - if c.certfile and c.keyfile: - kwargs['cert'] = (c.certfile, c.keyfile) - kwargs['timeout'] = c.timeout - - return cls._make(**kwargs) - - @staticmethod - def register_cli_options(parser): - """Register the argparse arguments that are needed for a session. - - :param argparse.ArgumentParser parser: parser to add to. - """ - parser.add_argument('--insecure', - default=False, - action='store_true', - help='Explicitly allow client to perform ' - '"insecure" TLS (https) requests. The ' - 'server\'s certificate will not be verified ' - 'against any certificate authorities. This ' - 'option should be used with caution.') - - parser.add_argument('--os-cacert', - metavar='', - default=os.environ.get('OS_CACERT'), - help='Specify a CA bundle file to use in ' - 'verifying a TLS (https) server certificate. ' - 'Defaults to env[OS_CACERT].') - - parser.add_argument('--os-cert', - metavar='', - default=os.environ.get('OS_CERT'), - help='Defaults to env[OS_CERT].') - - parser.add_argument('--os-key', - metavar='', - default=os.environ.get('OS_KEY'), - help='Defaults to env[OS_KEY].') - - parser.add_argument('--timeout', - default=600, - type=_positive_non_zero_float, - metavar='', - help='Set request timeout (in seconds).') - - @classmethod - def load_from_cli_options(cls, args, **kwargs): - """Create a :py:class:`.Session` object from CLI arguments. - - The CLI arguments must have been registered with - :py:meth:`.register_cli_options`. - - :param Namespace args: result of parsed arguments. - - :returns: A new session object. - :rtype: :py:class:`.Session` - """ - kwargs['insecure'] = args.insecure - kwargs['cacert'] = args.os_cacert - if args.os_cert and args.os_key: - kwargs['cert'] = (args.os_cert, args.os_key) - kwargs['timeout'] = args.timeout - - return cls._make(**kwargs) - - -class TCPKeepAliveAdapter(requests.adapters.HTTPAdapter): - """The custom adapter used to set TCP Keep-Alive on all connections. - - This Adapter also preserves the default behaviour of Requests which - disables Nagle's Algorithm. See also: - http://blogs.msdn.com/b/windowsazurestorage/archive/2010/06/25/nagle-s-algorithm-is-not-friendly-towards-small-requests.aspx - """ - - def init_poolmanager(self, *args, **kwargs): - if 'socket_options' not in kwargs: - socket_options = [ - # Keep Nagle's algorithm off - (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1), - # Turn on TCP Keep-Alive - (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), - ] - - # Some operating systems (e.g., OSX) do not support setting - # keepidle - if hasattr(socket, 'TCP_KEEPIDLE'): - socket_options += [ - # Wait 60 seconds before sending keep-alive probes - (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60) - ] - - # TODO(claudiub): Windows does not contain the TCP_KEEPCNT and - # TCP_KEEPINTVL socket attributes. Instead, it contains - # SIO_KEEPALIVE_VALS, which can be set via ioctl, which should be - # set once it is available in requests. - # https://msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx - if hasattr(socket, 'TCP_KEEPCNT'): - socket_options += [ - # Set the maximum number of keep-alive probes - (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4) - ] - - if hasattr(socket, 'TCP_KEEPINTVL'): - socket_options += [ - # Send keep-alive probes every 15 seconds - (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15) - ] - - # After waiting 60 seconds, and then sending a probe once every 15 - # seconds 4 times, these options should ensure that a connection - # hands for no longer than 2 minutes before a ConnectionError is - # raised. - - kwargs['socket_options'] = socket_options - super(TCPKeepAliveAdapter, self).init_poolmanager(*args, **kwargs) diff --git a/keystoneclient/tests/__init__.py b/keystoneclient/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/__init__.py b/keystoneclient/tests/functional/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/base.py b/keystoneclient/tests/functional/base.py deleted file mode 100644 index 743cb501..00000000 --- a/keystoneclient/tests/functional/base.py +++ /dev/null @@ -1,89 +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. - -import testtools - -from keystoneclient import client -import os_client_config - -IDENTITY_CLIENT = 'identity' -OPENSTACK_CLOUDS = ('functional_admin', 'devstack-admin', 'envvars') - - -def get_client(version): - """Create a keystoneclient instance to run functional tests. - - The client is instantiated via os-client-config either based on a - clouds.yaml config file or from the environment variables. - - First, look for a 'functional_admin' cloud, as this is a cloud that the - user may have defined for functional testing with admin credentials. If - that is not found, check for the 'devstack-admin' cloud. Finally, fall - back to looking for environment variables. - - """ - for cloud in OPENSTACK_CLOUDS: - try: - cloud_config = os_client_config.get_config( - cloud=cloud, identity_api_version=version) - return cloud_config.get_legacy_client(service_key=IDENTITY_CLIENT, - constructor=client.Client) - - except os_client_config.exceptions.OpenStackConfigException: - pass - - raise Exception("Could not find any cloud definition for clouds named" - " functional_admin or devstack-admin. Check your" - " clouds.yaml file or your envvars and try again.") - - -class ClientTestCase(testtools.TestCase): - - def setUp(self): - super(ClientTestCase, self).setUp() - - if not self.auth_ref.project_scoped: - raise Exception("Could not run functional tests, which are " - "run based on the scope provided for " - "authentication. Please provide a project " - "scope information.") - - @property - def client(self): - if not hasattr(self, '_client'): - self._client = get_client(self.version) - - return self._client - - @property - def auth_ref(self): - return self.client.session.auth.get_auth_ref(self.client.session) - - @property - def project_domain_id(self): - return self.auth_ref.project_domain_id - - @property - def project_id(self): - return self.client.session.get_project_id() - - @property - def user_id(self): - return self.client.session.get_user_id() - - -class V3ClientTestCase(ClientTestCase): - version = '3' - - -class V2ClientTestCase(ClientTestCase): - version = '2.0' diff --git a/keystoneclient/tests/functional/hooks/post_test_hook.sh b/keystoneclient/tests/functional/hooks/post_test_hook.sh deleted file mode 100755 index 951c321c..00000000 --- a/keystoneclient/tests/functional/hooks/post_test_hook.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -xe - -# 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 is executed inside post_test_hook function in devstack gate. - -function generate_testr_results { - if [ -f .testrepository/0 ]; then - sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit - sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit - sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html - sudo gzip -9 $BASE/logs/testrepository.subunit - sudo gzip -9 $BASE/logs/testr_results.html - sudo chown jenkins:jenkins $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - fi -} - -export KEYSTONECLIENT_DIR="$BASE/new/python-keystoneclient" - -# Get admin credentials -cd $BASE/new/devstack -source openrc admin admin - -# Go to the keystoneclient dir -cd $KEYSTONECLIENT_DIR - -sudo chown -R jenkins:stack $KEYSTONECLIENT_DIR - -# Run tests -echo "Running keystoneclient functional test suite" -set +e -# Preserve env for OS_ credentials -sudo -E -H -u jenkins tox -efunctional -EXIT_CODE=$? -set -e - -# Collect and parse result -generate_testr_results -exit $EXIT_CODE diff --git a/keystoneclient/tests/functional/test_access.py b/keystoneclient/tests/functional/test_access.py deleted file mode 100644 index 0b202fb6..00000000 --- a/keystoneclient/tests/functional/test_access.py +++ /dev/null @@ -1,50 +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. - -import os - -import testtools - -from keystoneclient.auth.identity import v2 -from keystoneclient import session -from tempest.lib import base - - -class TestV2AccessInfo(base.BaseTestCase): - - def setUp(self): - super(TestV2AccessInfo, self).setUp() - - self.session = session.Session() - - @testtools.skip("likely race condition, being skipped") - def test_access_audit_id(self): - unscoped_plugin = v2.Password(auth_url=os.environ.get('OS_AUTH_URL'), - username=os.environ.get('OS_USERNAME'), - password=os.environ.get('OS_PASSWORD')) - - unscoped_auth_ref = unscoped_plugin.get_access(self.session) - - self.assertIsNotNone(unscoped_auth_ref.audit_id) - self.assertIsNone(unscoped_auth_ref.audit_chain_id) - - scoped_plugin = v2.Token(auth_url=os.environ.get('OS_AUTH_URL'), - token=unscoped_auth_ref.auth_token, - tenant_name=os.environ.get('OS_TENANT_NAME')) - - scoped_auth_ref = scoped_plugin.get_access(self.session) - - self.assertIsNotNone(scoped_auth_ref.audit_id) - self.assertIsNotNone(scoped_auth_ref.audit_chain_id) - - self.assertEqual(unscoped_auth_ref.audit_id, - scoped_auth_ref.audit_chain_id) diff --git a/keystoneclient/tests/functional/test_base.py b/keystoneclient/tests/functional/test_base.py deleted file mode 100644 index d5f05166..00000000 --- a/keystoneclient/tests/functional/test_base.py +++ /dev/null @@ -1,28 +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. - -import keystoneclient -from keystoneclient.tests.functional import base - - -class V3ClientVersionTestCase(base.V3ClientTestCase): - - def test_version(self): - self.assertIsInstance(self.client, - keystoneclient.v3.client.Client) - - -class V2ClientVersionTestCase(base.V2ClientTestCase): - - def test_version(self): - self.assertIsInstance(self.client, - keystoneclient.v2_0.client.Client) diff --git a/keystoneclient/tests/functional/v2_0/__init__.py b/keystoneclient/tests/functional/v2_0/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/v3/__init__.py b/keystoneclient/tests/functional/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/v3/client_fixtures.py b/keystoneclient/tests/functional/v3/client_fixtures.py deleted file mode 100644 index dd7209a6..00000000 --- a/keystoneclient/tests/functional/v3/client_fixtures.py +++ /dev/null @@ -1,250 +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. - -import fixtures -import uuid - - -RESOURCE_NAME_PREFIX = 'keystoneclient-functional-' - - -class Base(fixtures.Fixture): - - def __init__(self, client, domain_id=None): - super(Base, self).__init__() - - self.client = client - self.domain_id = domain_id - self.ref = None - self.entity = None - - def __getattr__(self, name): - """Return the attribute from the represented entity.""" - return getattr(self.entity, name) - - -class User(Base): - - def setUp(self): - super(User, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.domain_id} - self.entity = self.client.users.create(**self.ref) - self.addCleanup(self.client.users.delete, self.entity) - - -class Group(Base): - - def setUp(self): - super(Group, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.domain_id} - self.entity = self.client.groups.create(**self.ref) - self.addCleanup(self.client.groups.delete, self.entity) - - -class Domain(Base): - - def setUp(self): - super(Domain, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'description': uuid.uuid4().hex, - 'enabled': True} - self.entity = self.client.domains.create(**self.ref) - - # Only disabled domains can be deleted - self.addCleanup(self.client.domains.delete, self.entity) - self.addCleanup(self.client.domains.update, self.entity, enabled=False) - - -class Project(Base): - - def __init__(self, client, domain_id=None, parent=None): - super(Project, self).__init__(client, domain_id) - self.parent = parent - - def setUp(self): - super(Project, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.domain_id, - 'enabled': True, - 'parent': self.parent} - self.entity = self.client.projects.create(**self.ref) - self.addCleanup(self.client.projects.delete, self.entity) - - -class Role(Base): - - def __init__(self, client, name=None, domain=None): - super(Role, self).__init__(client) - self.name = name or RESOURCE_NAME_PREFIX + uuid.uuid4().hex - self.domain = domain - - def setUp(self): - super(Role, self).setUp() - - self.ref = {'name': self.name, - 'domain': self.domain} - self.entity = self.client.roles.create(**self.ref) - self.addCleanup(self.client.roles.delete, self.entity) - - -class InferenceRule(Base): - - def __init__(self, client, prior_role, implied_role): - super(InferenceRule, self).__init__(client) - self.prior_role = prior_role - self.implied_role = implied_role - - def setUp(self): - super(InferenceRule, self).setUp() - - self.ref = {'prior_role': self.prior_role, - 'implied_role': self.implied_role} - self.entity = self.client.inference_rules.create(**self.ref) - self.addCleanup(self.client.inference_rules.delete, self.prior_role, - self.implied_role) - - -class Service(Base): - - def setUp(self): - super(Service, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'type': uuid.uuid4().hex, - 'enabled': True, - 'description': uuid.uuid4().hex} - self.entity = self.client.services.create(**self.ref) - self.addCleanup(self.client.services.delete, self.entity) - - -class Policy(Base): - - def setUp(self): - super(Policy, self).setUp() - - self.ref = {'blob': uuid.uuid4().hex, - 'type': uuid.uuid4().hex} - self.entity = self.client.policies.create(**self.ref) - self.addCleanup(self.client.policies.delete, self.entity) - - -class Region(Base): - - def __init__(self, client, parent_region=None): - super(Region, self).__init__(client) - self.parent_region = parent_region - - def setUp(self): - super(Region, self).setUp() - - self.ref = {'description': uuid.uuid4().hex, - 'parent_region': self.parent_region} - self.entity = self.client.regions.create(**self.ref) - self.addCleanup(self.client.regions.delete, self.entity) - - -class Endpoint(Base): - - def __init__(self, client, service, interface, region=None): - super(Endpoint, self).__init__(client) - self.service = service - self.interface = interface - self.region = region - - def setUp(self): - super(Endpoint, self).setUp() - - self.ref = {'service': self.service, - 'url': 'http://' + uuid.uuid4().hex, - 'enabled': True, - 'interface': self.interface, - 'region': self.region} - self.entity = self.client.endpoints.create(**self.ref) - self.addCleanup(self.client.endpoints.delete, self.entity) - - -class EndpointGroup(Base): - - def setUp(self): - super(EndpointGroup, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'filters': {'interface': 'public'}, - 'description': uuid.uuid4().hex} - self.entity = self.client.endpoint_groups.create(**self.ref) - self.addCleanup(self.client.endpoint_groups.delete, self.entity) - - -class Credential(Base): - - def __init__(self, client, user, type, project=None): - super(Credential, self).__init__(client) - self.user = user - self.type = type - self.project = project - - if type == 'ec2': - self.blob = ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}") - else: - self.blob = uuid.uuid4().hex - - def setUp(self): - super(Credential, self).setUp() - - self.ref = {'user': self.user, - 'type': self.type, - 'blob': self.blob, - 'project': self.project} - self.entity = self.client.credentials.create(**self.ref) - self.addCleanup(self.client.credentials.delete, self.entity) - - -class EC2(Base): - - def __init__(self, client, user_id, project_id): - super(EC2, self).__init__(client) - self.user_id = user_id - self.project_id = project_id - - def setUp(self): - super(EC2, self).setUp() - - self.ref = {'user_id': self.user_id, - 'project_id': self.project_id} - self.entity = self.client.ec2.create(**self.ref) - self.addCleanup(self.client.ec2.delete, - self.user_id, - self.entity.access) - - -class DomainConfig(Base): - - def __init__(self, client, domain_id): - super(DomainConfig, self).__init__(client, domain_id=domain_id) - self.domain_id = domain_id - - def setUp(self): - super(DomainConfig, self).setUp() - - self.ref = {'identity': {'driver': uuid.uuid4().hex}, - 'ldap': {'url': uuid.uuid4().hex}} - self.entity = self.client.domain_configs.create( - self.domain_id, self.ref) - self.addCleanup(self.client.domain_configs.delete, - self.domain_id) diff --git a/keystoneclient/tests/functional/v3/test_credentials.py b/keystoneclient/tests/functional/v3/test_credentials.py deleted file mode 100644 index a5d00b1c..00000000 --- a/keystoneclient/tests/functional/v3/test_credentials.py +++ /dev/null @@ -1,194 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class CredentialsTestCase(base.V3ClientTestCase): - - def setUp(self): - super(CredentialsTestCase, self).setUp() - self.test_domain = fixtures.Domain(self.client) - self.useFixture(self.test_domain) - - def check_credential(self, credential, credential_ref=None): - self.assertIsNotNone(credential.id) - self.assertIn('self', credential.links) - self.assertIn('/credentials/' + credential.id, - credential.links['self']) - - if credential_ref: - self.assertEqual(credential_ref['user'], credential.user_id) - self.assertEqual(credential_ref['type'], credential.type) - self.assertEqual(credential_ref['blob'], credential.blob) - - # There is no guarantee below attributes are present in credential - if credential_ref['type'] == 'ec2' or hasattr(credential_ref, - 'project'): - self.assertEqual(credential_ref['project'], - credential.project_id) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(credential.user_id) - self.assertIsNotNone(credential.type) - self.assertIsNotNone(credential.blob) - if credential.type == 'ec2': - self.assertIsNotNone(credential.project_id) - - def test_create_credential_of_cert_type(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - credential_ref = {'user': user.id, - 'type': 'cert', - 'blob': uuid.uuid4().hex} - credential = self.client.credentials.create(**credential_ref) - - self.addCleanup(self.client.credentials.delete, credential) - self.check_credential(credential, credential_ref) - - def test_create_credential_of_ec2_type(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - # project is mandatory attribute if the credential type is ec2 - credential_ref = {'user': user.id, - 'type': 'ec2', - 'blob': ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}")} - self.assertRaises(http.BadRequest, - self.client.credentials.create, - **credential_ref) - - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - credential_ref = {'user': user.id, - 'type': 'ec2', - 'blob': ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}"), - 'project': project.id} - credential = self.client.credentials.create(**credential_ref) - - self.addCleanup(self.client.credentials.delete, credential) - self.check_credential(credential, credential_ref) - - def test_create_credential_of_totp_type(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - credential_ref = {'user': user.id, - 'type': 'totp', - 'blob': uuid.uuid4().hex} - credential = self.client.credentials.create(**credential_ref) - - self.addCleanup(self.client.credentials.delete, credential) - self.check_credential(credential, credential_ref) - - def test_get_credential(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - for credential_type in ['cert', 'ec2', 'totp']: - credential = fixtures.Credential(self.client, user=user.id, - type=credential_type, - project=project.id) - self.useFixture(credential) - - credential_ret = self.client.credentials.get(credential.id) - self.check_credential(credential_ret, credential.ref) - - def test_list_credentials(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - cert_credential = fixtures.Credential(self.client, user=user.id, - type='cert') - self.useFixture(cert_credential) - - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - ec2_credential = fixtures.Credential(self.client, user=user.id, - type='ec2', project=project.id) - self.useFixture(ec2_credential) - - totp_credential = fixtures.Credential(self.client, user=user.id, - type='totp') - self.useFixture(totp_credential) - - credentials = self.client.credentials.list() - - # All credentials are valid - for credential in credentials: - self.check_credential(credential) - - self.assertIn(cert_credential.entity, credentials) - self.assertIn(ec2_credential.entity, credentials) - self.assertIn(totp_credential.entity, credentials) - - def test_update_credential(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - new_user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(new_user) - new_project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(new_project) - - credential = fixtures.Credential(self.client, user=user.id, - type='cert') - self.useFixture(credential) - - new_type = 'ec2' - new_blob = ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}") - - credential_ret = self.client.credentials.update(credential.id, - user=new_user.id, - type=new_type, - blob=new_blob, - project=new_project.id) - - credential.ref.update({'user': new_user.id, 'type': new_type, - 'blob': new_blob, 'project': new_project.id}) - self.check_credential(credential_ret, credential.ref) - - def test_delete_credential(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - for credential_type in ['cert', 'ec2', 'totp']: - - if credential_type == 'ec2': - blob_value = ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}") - else: - blob_value = uuid.uuid4().hex - - credential = self.client.credentials.create(user=user.id, - type=credential_type, - blob=blob_value, - project=project.id) - self.client.credentials.delete(credential.id) - self.assertRaises(http.NotFound, - self.client.credentials.get, - credential.id) diff --git a/keystoneclient/tests/functional/v3/test_domain_configs.py b/keystoneclient/tests/functional/v3/test_domain_configs.py deleted file mode 100644 index f3ca71a2..00000000 --- a/keystoneclient/tests/functional/v3/test_domain_configs.py +++ /dev/null @@ -1,106 +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. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class DomainConfigsTestCase(base.V3ClientTestCase): - - def setUp(self): - super(DomainConfigsTestCase, self).setUp() - self.test_domain = fixtures.Domain(self.client) - self.useFixture(self.test_domain) - - def check_domain_config(self, config, config_ref): - for attr in config_ref: - self.assertEqual( - getattr(config, attr), - config_ref[attr], - 'Expected different %s' % attr) - - def _new_ref(self): - return {'identity': {'driver': uuid.uuid4().hex}, - 'ldap': {'url': uuid.uuid4().hex}} - - def test_create_domain_config(self): - config_ref = self._new_ref() - config = self.client.domain_configs.create( - self.test_domain.id, config_ref) - self.addCleanup( - self.client.domain_configs.delete, self.test_domain.id) - self.check_domain_config(config, config_ref) - - def test_create_invalid_domain_config(self): - invalid_groups_ref = { - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}, - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.create, - self.test_domain.id, - invalid_groups_ref) - - invalid_options_ref = { - 'identity': {uuid.uuid4().hex: uuid.uuid4().hex}, - 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.create, - self.test_domain.id, - invalid_options_ref) - - def test_get_domain_config(self): - config = fixtures.DomainConfig(self.client, self.test_domain.id) - self.useFixture(config) - - config_ret = self.client.domain_configs.get(self.test_domain.id) - self.check_domain_config(config_ret, config.ref) - - def test_update_domain_config(self): - config = fixtures.DomainConfig(self.client, self.test_domain.id) - self.useFixture(config) - - update_config_ref = self._new_ref() - config_ret = self.client.domain_configs.update( - self.test_domain.id, update_config_ref) - self.check_domain_config(config_ret, update_config_ref) - - def test_update_invalid_domain_config(self): - config = fixtures.DomainConfig(self.client, self.test_domain.id) - self.useFixture(config) - - invalid_groups_ref = { - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}, - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.update, - self.test_domain.id, - invalid_groups_ref) - - invalid_options_ref = { - 'identity': {uuid.uuid4().hex: uuid.uuid4().hex}, - 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.update, - self.test_domain.id, - invalid_options_ref) - - def test_domain_config_delete(self): - config_ref = self._new_ref() - self.client.domain_configs.create(self.test_domain.id, config_ref) - - self.client.domain_configs.delete(self.test_domain.id) - self.assertRaises(http.NotFound, - self.client.domain_configs.get, - self.project_domain_id) diff --git a/keystoneclient/tests/functional/v3/test_domains.py b/keystoneclient/tests/functional/v3/test_domains.py deleted file mode 100644 index cdfbdd74..00000000 --- a/keystoneclient/tests/functional/v3/test_domains.py +++ /dev/null @@ -1,97 +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. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class DomainsTestCase(base.V3ClientTestCase): - - def check_domain(self, domain, domain_ref=None): - self.assertIsNotNone(domain.id) - self.assertIn('self', domain.links) - self.assertIn('/domains/' + domain.id, domain.links['self']) - - if domain_ref: - self.assertEqual(domain_ref['name'], domain.name) - self.assertEqual(domain_ref['enabled'], domain.enabled) - - # There is no guarantee description is present in domain - if hasattr(domain_ref, 'description'): - self.assertEqual(domain_ref['description'], domain.description) - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(domain.name) - self.assertIsNotNone(domain.enabled) - - def test_create_domain(self): - domain_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'description': uuid.uuid4().hex, - 'enabled': True} - domain = self.client.domains.create(**domain_ref) - self.check_domain(domain, domain_ref) - - # Only disabled domains can be deleted - self.addCleanup(self.client.domains.delete, domain) - self.addCleanup(self.client.domains.update, domain, enabled=False) - - def test_get_domain(self): - domain_id = self.project_domain_id - domain_ret = self.client.domains.get(domain_id) - self.check_domain(domain_ret) - - def test_list_domains(self): - domain_one = fixtures.Domain(self.client) - self.useFixture(domain_one) - - domain_two = fixtures.Domain(self.client) - self.useFixture(domain_two) - - domains = self.client.domains.list() - - # All domains are valid - for domain in domains: - self.check_domain(domain) - - self.assertIn(domain_one.entity, domains) - self.assertIn(domain_two.entity, domains) - - def test_update_domain(self): - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - new_description = uuid.uuid4().hex - domain_ret = self.client.domains.update(domain.id, - description=new_description) - - domain.ref.update({'description': new_description}) - self.check_domain(domain_ret, domain.ref) - - def test_delete_domain(self): - domain = self.client.domains.create(name=uuid.uuid4().hex, - description=uuid.uuid4().hex, - enabled=True) - - # Only disabled domains can be deleted - self.assertRaises(http.Forbidden, - self.client.domains.delete, - domain.id) - - self.client.domains.update(domain, enabled=False) - self.client.domains.delete(domain.id) - self.assertRaises(http.NotFound, - self.client.domains.get, - domain.id) diff --git a/keystoneclient/tests/functional/v3/test_ec2.py b/keystoneclient/tests/functional/v3/test_ec2.py deleted file mode 100644 index 09703b0d..00000000 --- a/keystoneclient/tests/functional/v3/test_ec2.py +++ /dev/null @@ -1,92 +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 keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class EC2TestCase(base.V3ClientTestCase): - - def check_ec2(self, ec2, ec2_ref=None): - self.assertIn('self', ec2.links) - self.assertIn('/users/%s/credentials/OS-EC2/%s' - % (ec2.user_id, ec2.access), ec2.links['self']) - - if ec2_ref: - self.assertEqual(ec2_ref['user_id'], ec2.user_id) - self.assertEqual(ec2_ref['project_id'], ec2.tenant_id) - - else: - self.assertIsNotNone(ec2.user_id) - self.assertIsNotNone(ec2.tenant_id) - - def test_create_ec2(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - ec2_ref = {'user_id': user.id, - 'project_id': project.id} - ec2 = self.client.ec2.create(**ec2_ref) - - self.addCleanup(self.client.ec2.delete, user.id, ec2.access) - self.check_ec2(ec2, ec2_ref) - - def test_get_ec2(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - ec2 = fixtures.EC2(self.client, user_id=user.id, project_id=project.id) - self.useFixture(ec2) - - ec2_ret = self.client.ec2.get(user.id, ec2.access) - self.check_ec2(ec2_ret, ec2.ref) - - def test_list_ec2(self): - user_one = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_one) - ec2_one = fixtures.EC2(self.client, user_id=user_one.id, - project_id=self.project_domain_id) - self.useFixture(ec2_one) - - user_two = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_two) - ec2_two = fixtures.EC2(self.client, user_id=user_two.id, - project_id=self.project_domain_id) - self.useFixture(ec2_two) - - ec2_list = self.client.ec2.list(user_one.id) - - # All ec2 are valid - for ec2 in ec2_list: - self.check_ec2(ec2) - - self.assertIn(ec2_one.entity, ec2_list) - self.assertNotIn(ec2_two.entity, ec2_list) - - def test_delete_ec2(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - ec2 = self.client.ec2.create(user.id, project.id) - - self.client.ec2.delete(user.id, ec2.access) - self.assertRaises(http.NotFound, - self.client.ec2.get, - user.id, ec2.access) diff --git a/keystoneclient/tests/functional/v3/test_endpoint_filters.py b/keystoneclient/tests/functional/v3/test_endpoint_filters.py deleted file mode 100644 index d8956bed..00000000 --- a/keystoneclient/tests/functional/v3/test_endpoint_filters.py +++ /dev/null @@ -1,86 +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 keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures -from keystoneclient.tests.functional.v3 import test_endpoint_groups -from keystoneclient.tests.functional.v3 import test_projects - - -class EndpointFiltersTestCase(base.V3ClientTestCase, - test_endpoint_groups.EndpointGroupsTestMixin, - test_projects.ProjectsTestMixin): - - def setUp(self): - super(EndpointFiltersTestCase, self).setUp() - - self.project = fixtures.Project(self.client) - self.endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(self.project) - self.useFixture(self.endpoint_group) - - self.client.endpoint_filter.add_endpoint_group_to_project( - self.endpoint_group, self.project) - - def test_add_endpoint_group_to_project(self): - project = fixtures.Project(self.client) - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(project) - self.useFixture(endpoint_group) - - self.client.endpoint_filter.add_endpoint_group_to_project( - endpoint_group, project) - self.client.endpoint_filter.check_endpoint_group_in_project( - endpoint_group, project) - - def test_delete_endpoint_group_from_project(self): - self.client.endpoint_filter.delete_endpoint_group_from_project( - self.endpoint_group, self.project) - self.assertRaises( - http.NotFound, - self.client.endpoint_filter.check_endpoint_group_in_project, - self.endpoint_group, self.project) - - def test_list_endpoint_groups_for_project(self): - endpoint_group_two = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group_two) - self.client.endpoint_filter.add_endpoint_group_to_project( - endpoint_group_two, self.project) - - endpoint_groups = ( - self.client.endpoint_filter.list_endpoint_groups_for_project( - self.project - ) - ) - - for endpoint_group in endpoint_groups: - self.check_endpoint_group(endpoint_group) - - self.assertIn(self.endpoint_group.entity, endpoint_groups) - self.assertIn(endpoint_group_two.entity, endpoint_groups) - - def test_list_projects_for_endpoint_group(self): - project_two = fixtures.Project(self.client) - self.useFixture(project_two) - self.client.endpoint_filter.add_endpoint_group_to_project( - self.endpoint_group, project_two) - - f = self.client.endpoint_filter.list_projects_for_endpoint_group - projects = f(self.endpoint_group) - - for project in projects: - self.check_project(project) - - self.assertIn(self.project.entity, projects) - self.assertIn(project_two.entity, projects) diff --git a/keystoneclient/tests/functional/v3/test_endpoint_groups.py b/keystoneclient/tests/functional/v3/test_endpoint_groups.py deleted file mode 100644 index 52fcf724..00000000 --- a/keystoneclient/tests/functional/v3/test_endpoint_groups.py +++ /dev/null @@ -1,123 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class EndpointGroupsTestMixin(object): - - def check_endpoint_group(self, endpoint_group, endpoint_group_ref=None): - self.assertIsNotNone(endpoint_group.id) - self.assertIn('self', endpoint_group.links) - self.assertIn('/endpoint_groups/' + endpoint_group.id, - endpoint_group.links['self']) - - if endpoint_group_ref: - self.assertEqual(endpoint_group_ref['name'], endpoint_group.name) - self.assertEqual(endpoint_group_ref['filters'], - endpoint_group.filters) - - # There is no guarantee description is present in endpoint groups - if hasattr(endpoint_group_ref, 'description'): - self.assertEqual(endpoint_group_ref['description'], - endpoint_group.description) - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(endpoint_group.name) - self.assertIsNotNone(endpoint_group.filters) - - -class EndpointGroupsTestCase(base.V3ClientTestCase, EndpointGroupsTestMixin): - - def test_create_endpoint_group(self): - endpoint_group_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'filters': {'interface': 'internal'}, - 'description': uuid.uuid4().hex} - endpoint_group = self.client.endpoint_groups.create( - **endpoint_group_ref) - - self.addCleanup(self.client.endpoint_groups.delete, endpoint_group) - self.check_endpoint_group(endpoint_group, endpoint_group_ref) - - def test_get_endpoint_group(self): - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group) - - endpoint_ret = self.client.endpoint_groups.get(endpoint_group.id) - self.check_endpoint_group(endpoint_ret, endpoint_group.ref) - - self.assertRaises(http.NotFound, - self.client.endpoint_groups.get, - uuid.uuid4().hex) - - def test_check_endpoint_group(self): - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group) - - self.client.endpoint_groups.check(endpoint_group.id) - self.assertRaises(http.NotFound, - self.client.endpoint_groups.check, - uuid.uuid4().hex) - - def test_list_endpoint_groups(self): - endpoint_group_one = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group_one) - - endpoint_group_two = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group_two) - - endpoint_groups = self.client.endpoint_groups.list() - - # All endpoints are valid - for endpoint_group in endpoint_groups: - self.check_endpoint_group(endpoint_group) - - self.assertIn(endpoint_group_one.entity, endpoint_groups) - self.assertIn(endpoint_group_two.entity, endpoint_groups) - - def test_update_endpoint_group(self): - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_filters = {'interface': 'public'} - new_description = uuid.uuid4().hex - - endpoint_group_ret = self.client.endpoint_groups.update( - endpoint_group, - name=new_name, - filters=new_filters, - description=new_description) - - endpoint_group.ref.update({'name': new_name, 'filters': new_filters, - 'description': new_description}) - self.check_endpoint_group(endpoint_group_ret, endpoint_group.ref) - - def test_delete_endpoint_group(self): - endpoint_group = self.client.endpoint_groups.create( - name=fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - filters={'interface': 'admin'}, - description=uuid.uuid4().hex) - - self.client.endpoint_groups.delete(endpoint_group.id) - self.assertRaises(http.NotFound, - self.client.endpoint_groups.check, - endpoint_group.id) - self.assertRaises(http.NotFound, - self.client.endpoint_groups.get, - endpoint_group.id) diff --git a/keystoneclient/tests/functional/v3/test_endpoints.py b/keystoneclient/tests/functional/v3/test_endpoints.py deleted file mode 100644 index c8379706..00000000 --- a/keystoneclient/tests/functional/v3/test_endpoints.py +++ /dev/null @@ -1,141 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class EndpointsTestCase(base.V3ClientTestCase): - - def check_endpoint(self, endpoint, endpoint_ref=None): - self.assertIsNotNone(endpoint.id) - self.assertIn('self', endpoint.links) - self.assertIn('/endpoints/' + endpoint.id, endpoint.links['self']) - - if endpoint_ref: - self.assertEqual(endpoint_ref['service'], endpoint.service_id) - self.assertEqual(endpoint_ref['url'], endpoint.url) - self.assertEqual(endpoint_ref['interface'], endpoint.interface) - self.assertEqual(endpoint_ref['enabled'], endpoint.enabled) - - # There is no guarantee below attributes are present in endpoint - if hasattr(endpoint_ref, 'region'): - self.assertEqual(endpoint_ref['region'], endpoint.region) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(endpoint.service_id) - self.assertIsNotNone(endpoint.url) - self.assertIsNotNone(endpoint.interface) - self.assertIsNotNone(endpoint.enabled) - - def test_create_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - endpoint_ref = {'service': service.id, - 'url': 'http://' + uuid.uuid4().hex, - 'enabled': True, - 'interface': 'public'} - endpoint = self.client.endpoints.create(**endpoint_ref) - - self.addCleanup(self.client.endpoints.delete, endpoint) - self.check_endpoint(endpoint, endpoint_ref) - - def test_get_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - interfaces = ['public', 'admin', 'internal'] - for interface in interfaces: - endpoint = fixtures.Endpoint(self.client, service.id, interface) - self.useFixture(endpoint) - endpoint_ret = self.client.endpoints.get(endpoint.id) - # All endpoints are valid - self.check_endpoint(endpoint_ret, endpoint.ref) - - def test_list_endpoints(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - region = fixtures.Region(self.client) - self.useFixture(region) - - endpoint_one = fixtures.Endpoint(self.client, service.id, 'public', - region=region.id) - self.useFixture(endpoint_one) - - endpoint_two = fixtures.Endpoint(self.client, service.id, 'admin', - region=region.id) - self.useFixture(endpoint_two) - - endpoint_three = fixtures.Endpoint(self.client, service.id, 'internal', - region=region.id) - self.useFixture(endpoint_three) - - endpoints = self.client.endpoints.list() - - # All endpoints are valid - for endpoint in endpoints: - self.check_endpoint(endpoint) - - self.assertIn(endpoint_one.entity, endpoints) - self.assertIn(endpoint_two.entity, endpoints) - self.assertIn(endpoint_three.entity, endpoints) - - def test_update_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - new_service = fixtures.Service(self.client) - self.useFixture(new_service) - - new_region = fixtures.Region(self.client) - self.useFixture(new_region) - - endpoint = fixtures.Endpoint(self.client, service.id, 'public') - self.useFixture(endpoint) - - new_url = 'http://' + uuid.uuid4().hex - new_interface = 'internal' - new_enabled = False - - endpoint_ret = self.client.endpoints.update(endpoint.id, - service=new_service.id, - url=new_url, - interface=new_interface, - enabled=new_enabled, - region=new_region.id) - - endpoint.ref.update({'service': new_service.id, 'url': new_url, - 'interface': new_interface, - 'enabled': new_enabled, - 'region': new_region.entity}) - self.check_endpoint(endpoint_ret, endpoint.ref) - - def test_delete_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - endpoint = self.client.endpoints.create(service=service.id, - url='http://' + - uuid.uuid4().hex, - enabled=True, - interface='public') - - self.client.endpoints.delete(endpoint.id) - self.assertRaises(http.NotFound, - self.client.endpoints.get, - endpoint.id) diff --git a/keystoneclient/tests/functional/v3/test_federation.py b/keystoneclient/tests/functional/v3/test_federation.py deleted file mode 100644 index da312662..00000000 --- a/keystoneclient/tests/functional/v3/test_federation.py +++ /dev/null @@ -1,106 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base - - -class TestIdentityProviders(base.V3ClientTestCase): - - def test_idp_create(self): - idp_id = uuid.uuid4().hex - # Create an identity provider just passing an ID - idp = self.client.federation.identity_providers.create(id=idp_id) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - self.assertEqual(idp_id, idp.id) - self.assertEqual([], idp.remote_ids) - self.assertFalse(idp.enabled) - - def test_idp_create_enabled_true(self): - # Create an enabled identity provider - idp_id = uuid.uuid4().hex - idp = self.client.federation.identity_providers.create( - id=idp_id, enabled=True) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - self.assertEqual(idp_id, idp.id) - self.assertEqual([], idp.remote_ids) - self.assertTrue(idp.enabled) - - def test_idp_create_with_remote_ids(self): - # Create an enabled identity provider with remote IDs - idp_id = uuid.uuid4().hex - remote_ids = [uuid.uuid4().hex, uuid.uuid4().hex] - idp = self.client.federation.identity_providers.create( - id=idp_id, enabled=True, remote_ids=remote_ids) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - self.assertEqual(idp_id, idp.id) - self.assertIn(remote_ids[0], idp.remote_ids) - self.assertIn(remote_ids[1], idp.remote_ids) - self.assertTrue(idp.enabled) - - def test_idp_list(self): - idp_ids = [] - for _ in range(3): - idp_id = uuid.uuid4().hex - self.client.federation.identity_providers.create(id=idp_id) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - idp_ids.append(idp_id) - - idp_list = self.client.federation.identity_providers.list() - fetched_ids = [fetched_idp.id for fetched_idp in idp_list] - for idp_id in idp_ids: - self.assertIn(idp_id, fetched_ids) - - def test_idp_get(self): - idp_id = uuid.uuid4().hex - remote_ids = [uuid.uuid4().hex, uuid.uuid4().hex] - idp_create = self.client.federation.identity_providers.create( - id=idp_id, enabled=True, remote_ids=remote_ids) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - idp_get = self.client.federation.identity_providers.get(idp_id) - self.assertEqual(idp_create.id, idp_get.id) - self.assertEqual(idp_create.enabled, idp_get.enabled) - self.assertIn(idp_create.remote_ids[0], idp_get.remote_ids) - self.assertIn(idp_create.remote_ids[1], idp_get.remote_ids) - - def test_idp_delete(self): - idp_id = uuid.uuid4().hex - self.client.federation.identity_providers.create(id=idp_id) - - # Get should not raise an error - self.client.federation.identity_providers.get(idp_id) - - # Delete it - self.client.federation.identity_providers.delete(idp_id) - - # Now get should raise an error - self.assertRaises( - http.NotFound, - self.client.federation.identity_providers.get, - idp_id) - - # Should not be present in the identity provider list - idp_list = self.client.federation.identity_providers.list() - fetched_ids = [fetched_idp.id for fetched_idp in idp_list] - self.assertNotIn(idp_id, fetched_ids) diff --git a/keystoneclient/tests/functional/v3/test_groups.py b/keystoneclient/tests/functional/v3/test_groups.py deleted file mode 100644 index 5e818ab1..00000000 --- a/keystoneclient/tests/functional/v3/test_groups.py +++ /dev/null @@ -1,94 +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. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class GroupsTestCase(base.V3ClientTestCase): - - def check_group(self, group, group_ref=None): - self.assertIsNotNone(group.id) - self.assertIn('self', group.links) - self.assertIn('/groups/' + group.id, group.links['self']) - - if group_ref: - self.assertEqual(group_ref['name'], group.name) - self.assertEqual(group_ref['domain'], group.domain_id) - - # There is no guarantee description is present in group - if hasattr(group_ref, 'description'): - self.assertEqual(group_ref['description'], group.description) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(group.name) - self.assertIsNotNone(group.domain_id) - - def test_create_group(self): - group_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id, - 'description': uuid.uuid4().hex} - - group = self.client.groups.create(**group_ref) - self.addCleanup(self.client.groups.delete, group) - self.check_group(group, group_ref) - - def test_get_group(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - group_ret = self.client.groups.get(group.id) - self.check_group(group_ret, group.ref) - - def test_list_groups(self): - group_one = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group_one) - - group_two = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group_two) - - groups = self.client.groups.list() - - # All groups are valid - for group in groups: - self.check_group(group) - - self.assertIn(group_one.entity, groups) - self.assertIn(group_two.entity, groups) - - def test_update_group(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_description = uuid.uuid4().hex - - group_ret = self.client.groups.update(group.id, - name=new_name, - description=new_description) - - group.ref.update({'name': new_name, 'description': new_description}) - self.check_group(group_ret, group.ref) - - def test_delete_group(self): - group = self.client.groups.create(name=uuid.uuid4().hex, - domain=self.project_domain_id) - - self.client.groups.delete(group.id) - self.assertRaises(http.NotFound, - self.client.groups.get, - group.id) diff --git a/keystoneclient/tests/functional/v3/test_implied_roles.py b/keystoneclient/tests/functional/v3/test_implied_roles.py deleted file mode 100644 index 0d5dbc5f..00000000 --- a/keystoneclient/tests/functional/v3/test_implied_roles.py +++ /dev/null @@ -1,74 +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.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -role_defs = ["test_admin", - "test_id_manager", - "test_resource_manager", - "test_role_manager", - "test_assignment_manager", - "test_domain_manager", - "test_project_manager", - "test_catalog_manager", - "test_policy_manager", - "test_observer", - "test_domain_tech_lead", - "test_project_observer", - "test_member"] - -inference_rules = {"test_admin": "test_id_manager", - "test_admin": "test_resource_manager", - "test_admin": "test_role_manager", - "test_admin": "test_catalog_manager", - "test_admin": "test_policy_manager", - "test_id_manager": "test_project_observer", - "test_resource_manager": "test_project_observer", - "test_role_manager": "test_project_observer", - "test_catalog_manager": "test_project_observer", - "test_policy_manager": "test_project_observer", - "test_project_observer": "test_observer", - "test_member": "test_observer"} - - -class TestImpliedRoles(base.V3ClientTestCase): - - def setUp(self): - super(TestImpliedRoles, self).setUp() - - def test_implied_roles(self): - initial_rule_count = ( - len(self.client.inference_rules.list_inference_roles())) - - self.create_roles() - self.create_rules() - rule_count = len(self.client.inference_rules.list_inference_roles()) - self.assertEqual(initial_rule_count + len(inference_rules), - rule_count) - - def role_dict(self): - roles = {role.name: role.id for role in self.client.roles.list()} - return roles - - def create_roles(self): - for role_def in role_defs: - role = fixtures.Role(self.client, name=role_def) - self.useFixture(role) - - def create_rules(self): - roles = self.role_dict() - for prior, implied in inference_rules.items(): - rule = fixtures.InferenceRule(self.client, roles[prior], - roles[implied]) - self.useFixture(rule) diff --git a/keystoneclient/tests/functional/v3/test_policies.py b/keystoneclient/tests/functional/v3/test_policies.py deleted file mode 100644 index 6ad0aae7..00000000 --- a/keystoneclient/tests/functional/v3/test_policies.py +++ /dev/null @@ -1,89 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class PoliciesTestCase(base.V3ClientTestCase): - - def check_policy(self, policy, policy_ref=None): - self.assertIsNotNone(policy.id) - self.assertIn('self', policy.links) - self.assertIn('/policies/' + policy.id, policy.links['self']) - - if policy_ref: - self.assertEqual(policy_ref['blob'], policy.blob) - self.assertEqual(policy_ref['type'], policy.type) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(policy.blob) - self.assertIsNotNone(policy.type) - - def test_create_policy(self): - policy_ref = {'blob': uuid.uuid4().hex, - 'type': uuid.uuid4().hex} - - policy = self.client.policies.create(**policy_ref) - self.addCleanup(self.client.policies.delete, policy) - self.check_policy(policy, policy_ref) - - def test_get_policy(self): - policy = fixtures.Policy(self.client) - self.useFixture(policy) - - policy_ret = self.client.policies.get(policy.id) - self.check_policy(policy_ret, policy.ref) - - def test_list_policies(self): - policy_one = fixtures.Policy(self.client) - self.useFixture(policy_one) - - policy_two = fixtures.Policy(self.client) - self.useFixture(policy_two) - - policies = self.client.policies.list() - - # All policies are valid - for policy in policies: - self.check_policy(policy) - - self.assertIn(policy_one.entity, policies) - self.assertIn(policy_two.entity, policies) - - def test_update_policy(self): - policy = fixtures.Policy(self.client) - self.useFixture(policy) - - new_blob = uuid.uuid4().hex - new_type = uuid.uuid4().hex - - policy_ret = self.client.policies.update(policy.id, - blob=new_blob, - type=new_type) - - policy.ref.update({'blob': new_blob, 'type': new_type}) - self.check_policy(policy_ret, policy.ref) - - def test_delete_policy(self): - policy = self.client.policies.create(blob=uuid.uuid4().hex, - type=uuid.uuid4().hex) - - self.client.policies.delete(policy.id) - self.assertRaises(http.NotFound, - self.client.policies.get, - policy.id) diff --git a/keystoneclient/tests/functional/v3/test_projects.py b/keystoneclient/tests/functional/v3/test_projects.py deleted file mode 100644 index 4b8d7493..00000000 --- a/keystoneclient/tests/functional/v3/test_projects.py +++ /dev/null @@ -1,190 +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. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient import exceptions -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class ProjectsTestMixin(object): - - def check_project(self, project, project_ref=None): - self.assertIsNotNone(project.id) - self.assertIn('self', project.links) - self.assertIn('/projects/' + project.id, project.links['self']) - - if project_ref: - self.assertEqual(project_ref['name'], project.name) - self.assertEqual(project_ref['domain'], project.domain_id) - self.assertEqual(project_ref['enabled'], project.enabled) - - # There is no guarantee the attributes below are present in project - if hasattr(project_ref, 'description'): - self.assertEqual(project_ref['description'], - project.description) - if hasattr(project_ref, 'parent'): - self.assertEqual(project_ref['parent'], project.parent) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(project.name) - self.assertIsNotNone(project.domain_id) - self.assertIsNotNone(project.enabled) - - -class ProjectsTestCase(base.V3ClientTestCase, ProjectsTestMixin): - - def setUp(self): - super(ProjectsTestCase, self).setUp() - self.test_domain = fixtures.Domain(self.client) - self.useFixture(self.test_domain) - - self.test_project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(self.test_project) - - def test_create_subproject(self): - project_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.test_domain.id, - 'enabled': True, - 'description': uuid.uuid4().hex, - 'parent': self.test_project.id} - - project = self.client.projects.create(**project_ref) - self.addCleanup(self.client.projects.delete, project) - self.check_project(project, project_ref) - - def test_create_project(self): - project_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.test_domain.id, - 'enabled': True, - 'description': uuid.uuid4().hex} - - project = self.client.projects.create(**project_ref) - self.addCleanup(self.client.projects.delete, project) - self.check_project(project, project_ref) - - def test_get_project(self): - project_ret = self.client.projects.get(self.test_project.id) - self.check_project(project_ret, self.test_project.ref) - - def test_get_project_invalid_params(self): - self.assertRaises(exceptions.ValidationError, - self.client.projects.get, - self.test_project.id, - subtree_as_list=True, subtree_as_ids=True) - self.assertRaises(exceptions.ValidationError, - self.client.projects.get, - self.test_project.id, - parents_as_list=True, parents_as_ids=True) - - def test_get_hierarchy_as_list(self): - project = fixtures.Project(self.client, self.test_domain.id, - parent=self.test_project.id) - self.useFixture(project) - - child_project = fixtures.Project(self.client, self.test_domain.id, - parent=project.id) - self.useFixture(child_project) - - # Only parents and subprojects that the current user has role - # assingments on are returned when asked for subtree_as_list and - # parents_as_list. - role = fixtures.Role(self.client) - self.useFixture(role) - self.client.roles.grant(role.id, user=self.user_id, - project=self.test_project.id) - self.client.roles.grant(role.id, user=self.user_id, - project=project.id) - self.client.roles.grant(role.id, user=self.user_id, - project=child_project.id) - - project_ret = self.client.projects.get(project.id, - subtree_as_list=True, - parents_as_list=True) - - self.check_project(project_ret, project.ref) - self.assertItemsEqual( - [{'project': self.test_project.entity.to_dict()}], - project_ret.parents) - self.assertItemsEqual( - [{'project': child_project.entity.to_dict()}], - project_ret.subtree) - - def test_get_hierarchy_as_ids(self): - project = fixtures.Project(self.client, self.test_domain.id, - parent=self.test_project.id) - self.useFixture(project) - - child_project = fixtures.Project(self.client, self.test_domain.id, - parent=project.id) - self.useFixture(child_project) - - project_ret = self.client.projects.get(project.id, - subtree_as_ids=True, - parents_as_ids=True) - - self.assertItemsEqual([self.test_project.id], project_ret.parents) - self.assertItemsEqual([child_project.id], project_ret.subtree) - - def test_list_projects(self): - project_one = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project_one) - - project_two = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project_two) - - projects = self.client.projects.list() - - # All projects are valid - for project in projects: - self.check_project(project) - - self.assertIn(project_one.entity, projects) - self.assertIn(project_two.entity, projects) - - def test_update_project(self): - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_description = uuid.uuid4().hex - project_ret = self.client.projects.update(project.id, - name=new_name, - enabled=False, - description=new_description) - - project.ref.update({'name': new_name, 'enabled': False, - 'description': new_description}) - self.check_project(project_ret, project.ref) - - def test_update_project_domain_not_allowed(self): - domain = fixtures.Domain(self.client) - self.useFixture(domain) - # Cannot update domain after project is created. - self.assertRaises(http.BadRequest, - self.client.projects.update, - self.test_project.id, domain=domain.id) - - def test_delete_project(self): - project = self.client.projects.create(name=uuid.uuid4().hex, - domain=self.test_domain.id, - enabled=True) - - self.client.projects.delete(project.id) - self.assertRaises(http.NotFound, - self.client.projects.get, - project.id) diff --git a/keystoneclient/tests/functional/v3/test_regions.py b/keystoneclient/tests/functional/v3/test_regions.py deleted file mode 100644 index 51f93863..00000000 --- a/keystoneclient/tests/functional/v3/test_regions.py +++ /dev/null @@ -1,85 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class RegionsTestCase(base.V3ClientTestCase): - - def check_region(self, region, region_ref=None): - self.assertIsNotNone(region.id) - self.assertIn('self', region.links) - self.assertIn('/regions/' + region.id, region.links['self']) - - # There is no guarantee the below attributes are present in region - if hasattr(region_ref, 'description'): - self.assertEqual(region_ref['description'], region.description) - if hasattr(region_ref, 'parent_region'): - self.assertEqual( - region_ref['parent_region'], - region.parent_region) - - def test_create_region(self): - region_ref = {'description': uuid.uuid4().hex} - - region = self.client.regions.create(**region_ref) - self.addCleanup(self.client.regions.delete, region) - self.check_region(region, region_ref) - - def test_get_region(self): - region = fixtures.Region(self.client) - self.useFixture(region) - - region_ret = self.client.regions.get(region.id) - self.check_region(region_ret, region.ref) - - def test_list_regions(self): - region_one = fixtures.Region(self.client) - self.useFixture(region_one) - - region_two = fixtures.Region(self.client, parent_region=region_one.id) - self.useFixture(region_two) - - regions = self.client.regions.list() - - # All regions are valid - for region in regions: - self.check_region(region) - - self.assertIn(region_one.entity, regions) - self.assertIn(region_two.entity, regions) - - def test_update_region(self): - parent = fixtures.Region(self.client) - self.useFixture(parent) - - region = fixtures.Region(self.client) - self.useFixture(region) - - new_description = uuid.uuid4().hex - region_ret = self.client.regions.update(region.id, - description=new_description, - parent_region=parent.id) - self.check_region(region_ret, region.ref) - - def test_delete_region(self): - region = self.client.regions.create() - - self.client.regions.delete(region.id) - self.assertRaises(http.NotFound, - self.client.regions.get, - region.id) diff --git a/keystoneclient/tests/functional/v3/test_roles.py b/keystoneclient/tests/functional/v3/test_roles.py deleted file mode 100644 index d2bc7a25..00000000 --- a/keystoneclient/tests/functional/v3/test_roles.py +++ /dev/null @@ -1,236 +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. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient import exceptions -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class RolesTestCase(base.V3ClientTestCase): - - def check_role(self, role, role_ref=None): - self.assertIsNotNone(role.id) - self.assertIn('self', role.links) - self.assertIn('/roles/' + role.id, role.links['self']) - - if role_ref: - self.assertEqual(role_ref['name'], role.name) - - # There is no guarantee domain is present in role - if hasattr(role_ref, 'domain'): - self.assertEqual(role_ref['domain'], role.domain_id) - - else: - # Only check remaining mandatory attribute - self.assertIsNotNone(role.name) - - def test_create_role(self): - role_ref = {'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex} - - role = self.client.roles.create(**role_ref) - self.addCleanup(self.client.roles.delete, role) - self.check_role(role, role_ref) - - def test_create_domain_role(self): - role_ref = {'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id} - - role = self.client.roles.create(**role_ref) - self.addCleanup(self.client.roles.delete, role) - self.check_role(role, role_ref) - - def test_get_role(self): - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - role_ret = self.client.roles.get(role.id) - self.check_role(role_ret, role.ref) - - def test_update_role_name(self): - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - role_ret = self.client.roles.update(role.id, - name=new_name) - - role.ref.update({'name': new_name}) - self.check_role(role_ret, role.ref) - - def test_update_role_domain(self): - role = fixtures.Role(self.client) - self.useFixture(role) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - new_domain = domain.id - role_ret = self.client.roles.update(role.id, - domain=new_domain) - - role.ref.update({'domain': new_domain}) - self.check_role(role_ret, role.ref) - - def test_list_roles_invalid_params(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - # Only filter in role grants for a user on a resource. - # Domain or project should be specified. - self.assertRaises(exceptions.ValidationError, - self.client.roles.list, - user=user.id) - - # Only filter in role grants for a group on a resource. - # Domain or project should be specified. - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - self.assertRaises(exceptions.ValidationError, - self.client.roles.list, - group=group.id) - - def test_list_roles(self): - global_role = fixtures.Role(self.client) - self.useFixture(global_role) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - domain_role = fixtures.Role(self.client, domain=domain.id) - self.useFixture(domain_role) - - global_roles = self.client.roles.list() - domain_roles = self.client.roles.list(domain_id=domain.id) - roles = global_roles + domain_roles - - # All roles are valid - for role in roles: - self.check_role(role) - - self.assertIn(global_role.entity, global_roles) - self.assertIn(domain_role.entity, domain_roles) - - def test_delete_role(self): - role = self.client.roles.create(name=uuid.uuid4().hex, - domain=self.project_domain_id) - - self.client.roles.delete(role.id) - self.assertRaises(http.NotFound, - self.client.roles.get, - role.id) - - def test_grant_role_invalid_params(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - # Only grant role to a group on a resource. - # Domain or project must be specified. - self.assertRaises(exceptions.ValidationError, - self.client.roles.grant, - role.id, - user=user.id) - - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - # Only grant role to a group on a resource. - # Domain or project must be specified. - self.assertRaises(exceptions.ValidationError, - self.client.roles.grant, - role.id, - group=group.id) - - def test_user_domain_grant_and_revoke(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, user=user.id, domain=domain.id) - roles_after_grant = self.client.roles.list(user=user.id, - domain=domain.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, user=user.id, domain=domain.id) - roles_after_revoke = self.client.roles.list(user=user.id, - domain=domain.id) - self.assertEqual(roles_after_revoke, []) - - def test_user_project_grant_and_revoke(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, user=user.id, project=project.id) - roles_after_grant = self.client.roles.list(user=user.id, - project=project.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, user=user.id, project=project.id) - roles_after_revoke = self.client.roles.list(user=user.id, - project=project.id) - self.assertEqual(roles_after_revoke, []) - - def test_group_domain_grant_and_revoke(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, group=group.id, domain=domain.id) - roles_after_grant = self.client.roles.list(group=group.id, - domain=domain.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, group=group.id, domain=domain.id) - roles_after_revoke = self.client.roles.list(group=group.id, - domain=domain.id) - self.assertEqual(roles_after_revoke, []) - - def test_group_project_grant_and_revoke(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, group=group.id, project=project.id) - roles_after_grant = self.client.roles.list(group=group.id, - project=project.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, group=group.id, project=project.id) - roles_after_revoke = self.client.roles.list(group=group.id, - project=project.id) - self.assertEqual(roles_after_revoke, []) diff --git a/keystoneclient/tests/functional/v3/test_services.py b/keystoneclient/tests/functional/v3/test_services.py deleted file mode 100644 index c17747d3..00000000 --- a/keystoneclient/tests/functional/v3/test_services.py +++ /dev/null @@ -1,106 +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. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class ServicesTestCase(base.V3ClientTestCase): - - def check_service(self, service, service_ref=None): - self.assertIsNotNone(service.id) - self.assertIn('self', service.links) - self.assertIn('/services/' + service.id, service.links['self']) - - if service_ref: - self.assertEqual(service_ref['name'], service.name) - self.assertEqual(service_ref['enabled'], service.enabled) - self.assertEqual(service_ref['type'], service.type) - - # There is no guarantee description is present in service - if hasattr(service_ref, 'description'): - self.assertEqual(service_ref['description'], - service.description) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(service.name) - self.assertIsNotNone(service.enabled) - self.assertIsNotNone(service.type) - - def test_create_service(self): - service_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'type': uuid.uuid4().hex, - 'enabled': True, - 'description': uuid.uuid4().hex} - - service = self.client.services.create(**service_ref) - - self.addCleanup(self.client.services.delete, service) - self.check_service(service, service_ref) - - def test_get_service(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - service_ret = self.client.services.get(service.id) - self.check_service(service_ret, service.ref) - - def test_list_services(self): - service_one = fixtures.Service(self.client) - self.useFixture(service_one) - - service_two = fixtures.Service(self.client) - self.useFixture(service_two) - - services = self.client.services.list() - - # All services are valid - for service in services: - self.check_service(service) - - self.assertIn(service_one.entity, services) - self.assertIn(service_two.entity, services) - - def test_update_service(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_type = uuid.uuid4().hex - new_enabled = False - new_description = uuid.uuid4().hex - - service_ret = self.client.services.update(service.id, - name=new_name, - type=new_type, - enabled=new_enabled, - description=new_description) - - service.ref.update({'name': new_name, 'type': new_type, - 'enabled': new_enabled, - 'description': new_description}) - self.check_service(service_ret, service.ref) - - def test_delete_service(self): - service = self.client.services.create(name=uuid.uuid4().hex, - type=uuid.uuid4().hex) - - self.client.services.delete(service.id) - self.assertRaises(http.NotFound, - self.client.services.get, - service.id) diff --git a/keystoneclient/tests/functional/v3/test_users.py b/keystoneclient/tests/functional/v3/test_users.py deleted file mode 100644 index 780ddbac..00000000 --- a/keystoneclient/tests/functional/v3/test_users.py +++ /dev/null @@ -1,140 +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. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class UsersTestCase(base.V3ClientTestCase): - - def check_user(self, user, user_ref=None): - self.assertIsNotNone(user.id) - self.assertIsNotNone(user.enabled) - self.assertIn('self', user.links) - self.assertIn('/users/' + user.id, user.links['self']) - - if user_ref: - self.assertEqual(user_ref['name'], user.name) - self.assertEqual(user_ref['domain'], user.domain_id) - # There is no guarantee the attributes below are present in user - if hasattr(user_ref, 'description'): - self.assertEqual(user_ref['description'], user.description) - if hasattr(user_ref, 'email'): - self.assertEqual(user_ref['email'], user.email) - if hasattr(user_ref, 'default_project'): - self.assertEqual(user_ref['default_project'], - user.default_project_id) - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(user.name) - self.assertIsNotNone(user.domain_id) - - def test_create_user(self): - user_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id, - 'default_project': self.project_id, - 'password': uuid.uuid4().hex, - 'description': uuid.uuid4().hex} - - user = self.client.users.create(**user_ref) - self.addCleanup(self.client.users.delete, user) - self.check_user(user, user_ref) - - def test_get_user(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - user_ret = self.client.users.get(user.id) - self.check_user(user_ret, user.ref) - - def test_list_users(self): - user_one = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_one) - - user_two = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_two) - - users = self.client.users.list() - - # All users are valid - for user in users: - self.check_user(user) - - self.assertIn(user_one.entity, users) - self.assertIn(user_two.entity, users) - - def test_list_users_with_filters(self): - suffix = uuid.uuid4().hex - user1_ref = { - 'name': 'test_user' + suffix, - 'domain': self.project_domain_id, - 'default_project': self.project_id, - 'password': uuid.uuid4().hex, - 'description': uuid.uuid4().hex} - - user2_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id, - 'default_project': self.project_id, - 'password': uuid.uuid4().hex, - 'description': uuid.uuid4().hex} - - user1 = self.client.users.create(**user1_ref) - self.client.users.create(**user2_ref) - - users = self.client.users.list(name__contains=['test_user', suffix]) - self.assertEqual(1, len(users)) - self.assertIn(user1, users) - - def test_update_user(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - new_description = uuid.uuid4().hex - user_ret = self.client.users.update(user.id, - description=new_description) - - user.ref.update({'description': new_description}) - self.check_user(user_ret, user.ref) - - def test_user_grouping(self): - # keystoneclient.v3.users owns user grouping operations, this is why - # this test case belongs to this class - user = fixtures.User(self.client, self.project_domain_id) - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(user) - self.useFixture(group) - - self.assertRaises(http.NotFound, - self.client.users.check_in_group, - user.id, group.id) - - self.client.users.add_to_group(user.id, group.id) - self.client.users.check_in_group(user.id, group.id) - self.client.users.remove_from_group(user.id, group.id) - - self.assertRaises(http.NotFound, - self.client.users.check_in_group, - user.id, group.id) - - def test_delete_user(self): - user = self.client.users.create(name=uuid.uuid4().hex, - domain=self.project_domain_id) - - self.client.users.delete(user.id) - self.assertRaises(http.NotFound, - self.client.users.get, - user.id) diff --git a/keystoneclient/tests/unit/__init__.py b/keystoneclient/tests/unit/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/apiclient/__init__.py b/keystoneclient/tests/unit/apiclient/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/apiclient/test_exceptions.py b/keystoneclient/tests/unit/apiclient/test_exceptions.py deleted file mode 100644 index 65cf0801..00000000 --- a/keystoneclient/tests/unit/apiclient/test_exceptions.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# 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 import exceptions -from keystoneclient.tests.unit import utils - - -class FakeResponse(object): - json_data = {} - - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) - - def json(self): - return self.json_data - - -class ExceptionsArgsTest(utils.TestCase): - - def assert_exception(self, ex_cls, method, url, status_code, json_data): - ex = exceptions.from_response( - FakeResponse(status_code=status_code, - headers={"Content-Type": "application/json"}, - json_data=json_data), - method, - url) - self.assertIsInstance(ex, ex_cls) - self.assertIn(json_data["error"]["message"], ex.message) - self.assertEqual(ex.details, json_data["error"]["details"]) - self.assertEqual(ex.method, method) - self.assertEqual(ex.url, url) - self.assertEqual(ex.http_status, status_code) - - def test_from_response_known(self): - method = "GET" - url = "/fake" - status_code = 400 - json_data = {"error": {"message": "fake message", - "details": "fake details"}} - self.assert_exception( - exceptions.BadRequest, method, url, status_code, json_data) - - def test_from_response_unknown(self): - method = "POST" - url = "/fake-unknown" - status_code = 499 - json_data = {"error": {"message": "fake unknown message", - "details": "fake unknown details"}} - self.assert_exception( - exceptions.HTTPClientError, method, url, status_code, json_data) - status_code = 600 - self.assert_exception( - exceptions.HTTPError, method, url, status_code, json_data) diff --git a/keystoneclient/tests/unit/auth/__init__.py b/keystoneclient/tests/unit/auth/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/auth/test_access.py b/keystoneclient/tests/unit/auth/test_access.py deleted file mode 100644 index f5f5843a..00000000 --- a/keystoneclient/tests/unit/auth/test_access.py +++ /dev/null @@ -1,64 +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. - -import uuid - -from keystoneauth1 import fixture -from keystoneauth1 import plugin - -from keystoneclient import access -from keystoneclient.auth.identity import access as access_plugin -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class AccessInfoPluginTests(utils.TestCase): - - def setUp(self): - super(AccessInfoPluginTests, self).setUp() - with self.deprecations.expect_deprecations_here(): - self.session = session.Session() - self.auth_token = uuid.uuid4().hex - - def _plugin(self, **kwargs): - token = fixture.V3Token() - s = token.add_service('identity') - s.add_standard_endpoints(public=self.TEST_ROOT_URL) - - auth_ref = access.AccessInfo.factory(body=token, - auth_token=self.auth_token) - with self.deprecations.expect_deprecations_here(): - return access_plugin.AccessInfoPlugin(auth_ref, **kwargs) - - def test_auth_ref(self): - plugin = self._plugin() - self.assertEqual(self.TEST_ROOT_URL, - plugin.get_endpoint(self.session, - service_type='identity', - interface='public')) - self.assertEqual(self.auth_token, plugin.get_token(session)) - - def test_auth_url(self): - auth_url = 'http://keystone.test.url' - plug = self._plugin(auth_url=auth_url) - - self.assertEqual(auth_url, - plug.get_endpoint(self.session, - interface=plugin.AUTH_INTERFACE)) - - def test_invalidate(self): - plugin = self._plugin() - auth_ref = plugin.auth_ref - - self.assertIsInstance(auth_ref, access.AccessInfo) - self.assertFalse(plugin.invalidate()) - self.assertIs(auth_ref, plugin.auth_ref) diff --git a/keystoneclient/tests/unit/auth/test_auth.py b/keystoneclient/tests/unit/auth/test_auth.py deleted file mode 100644 index f2884350..00000000 --- a/keystoneclient/tests/unit/auth/test_auth.py +++ /dev/null @@ -1,38 +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 import auth -from keystoneclient.auth import identity -from keystoneclient.tests.unit.auth import utils - - -class AuthTests(utils.TestCase): - - def test_plugin_names_in_available(self): - with self.deprecations.expect_deprecations_here(): - plugins = auth.get_available_plugin_names() - - for p in ('password', 'v2password', 'v3password', - 'token', 'v2token', 'v3token'): - self.assertIn(p, plugins) - - def test_plugin_classes_in_available(self): - with self.deprecations.expect_deprecations_here(): - plugins = auth.get_available_plugin_classes() - - self.assertIs(plugins['password'], identity.Password) - self.assertIs(plugins['v2password'], identity.V2Password) - self.assertIs(plugins['v3password'], identity.V3Password) - - self.assertIs(plugins['token'], identity.Token) - self.assertIs(plugins['v2token'], identity.V2Token) - self.assertIs(plugins['v3token'], identity.V3Token) diff --git a/keystoneclient/tests/unit/auth/test_cli.py b/keystoneclient/tests/unit/auth/test_cli.py deleted file mode 100644 index b6fefa7c..00000000 --- a/keystoneclient/tests/unit/auth/test_cli.py +++ /dev/null @@ -1,197 +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. - -import argparse -import uuid - -import fixtures -import mock -from oslo_config import cfg - -from keystoneclient.auth import base -from keystoneclient.auth import cli -from keystoneclient.tests.unit.auth import utils - - -class TesterPlugin(base.BaseAuthPlugin): - - def get_token(self, *args, **kwargs): - return None - - @classmethod - def get_options(cls): - # NOTE(jamielennox): this is kind of horrible. If you specify this as - # a deprecated_name= value it will convert - to _ which is not what we - # want for a CLI option. - deprecated = [cfg.DeprecatedOpt('test-other')] - return [ - cfg.StrOpt('test-opt', help='tester', deprecated_opts=deprecated) - ] - - -class CliTests(utils.TestCase): - - def setUp(self): - super(CliTests, self).setUp() - self.deprecations.expect_deprecations() - self.p = argparse.ArgumentParser() - - def env(self, name, value=None): - if value is not None: - # environment variables are always strings - value = str(value) - - return self.useFixture(fixtures.EnvironmentVariable(name, value)) - - def test_creating_with_no_args(self): - ret = cli.register_argparse_arguments(self.p, []) - self.assertIsNone(ret) - self.assertIn('--os-auth-plugin', self.p.format_usage()) - - def test_load_with_nothing(self): - cli.register_argparse_arguments(self.p, []) - opts = self.p.parse_args([]) - self.assertIsNone(cli.load_from_argparse_arguments(opts)) - - @utils.mock_plugin - def test_basic_params_added(self, m): - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name] - ret = cli.register_argparse_arguments(self.p, argv) - self.assertIs(utils.MockPlugin, ret) - - for n in ('--os-a-int', '--os-a-bool', '--os-a-float'): - self.assertIn(n, self.p.format_usage()) - - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_param_loading(self, m): - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name, - '--os-a-int', str(self.a_int), - '--os-a-float', str(self.a_float), - '--os-a-bool', str(self.a_bool)] - - klass = cli.register_argparse_arguments(self.p, argv) - self.assertIs(utils.MockPlugin, klass) - - opts = self.p.parse_args(argv) - self.assertEqual(name, opts.os_auth_plugin) - - a = cli.load_from_argparse_arguments(opts) - self.assertTestVals(a) - - self.assertEqual(name, opts.os_auth_plugin) - self.assertEqual(str(self.a_int), opts.os_a_int) - self.assertEqual(str(self.a_float), opts.os_a_float) - self.assertEqual(str(self.a_bool), opts.os_a_bool) - - @utils.mock_plugin - def test_default_options(self, m): - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name, - '--os-a-float', str(self.a_float)] - - klass = cli.register_argparse_arguments(self.p, argv) - self.assertIs(utils.MockPlugin, klass) - - opts = self.p.parse_args(argv) - self.assertEqual(name, opts.os_auth_plugin) - - a = cli.load_from_argparse_arguments(opts) - - self.assertEqual(self.a_float, a['a_float']) - self.assertEqual(3, a['a_int']) - - @utils.mock_plugin - def test_with_default_string_value(self, m): - name = uuid.uuid4().hex - klass = cli.register_argparse_arguments(self.p, [], default=name) - self.assertIs(utils.MockPlugin, klass) - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_overrides_default_string_value(self, m): - name = uuid.uuid4().hex - default = uuid.uuid4().hex - argv = ['--os-auth-plugin', name] - klass = cli.register_argparse_arguments(self.p, argv, default=default) - self.assertIs(utils.MockPlugin, klass) - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_with_default_type_value(self, m): - klass = cli.register_argparse_arguments(self.p, [], - default=utils.MockPlugin) - self.assertIs(utils.MockPlugin, klass) - self.assertEqual(0, m.call_count) - - @utils.mock_plugin - def test_overrides_default_type_value(self, m): - # using this test plugin would fail if called because there - # is no get_options() function - class TestPlugin(object): - pass - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name] - klass = cli.register_argparse_arguments(self.p, argv, - default=TestPlugin) - self.assertIs(utils.MockPlugin, klass) - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_env_overrides_default_opt(self, m): - name = uuid.uuid4().hex - val = uuid.uuid4().hex - self.env('OS_A_STR', val) - - klass = cli.register_argparse_arguments(self.p, [], default=name) - opts = self.p.parse_args([]) - a = klass.load_from_argparse_arguments(opts) - - self.assertEqual(val, a['a_str']) - - def test_deprecated_cli_options(self): - TesterPlugin.register_argparse_arguments(self.p) - val = uuid.uuid4().hex - opts = self.p.parse_args(['--os-test-other', val]) - self.assertEqual(val, opts.os_test_opt) - - def test_deprecated_multi_cli_options(self): - TesterPlugin.register_argparse_arguments(self.p) - val1 = uuid.uuid4().hex - val2 = uuid.uuid4().hex - # argarse rules say that the last specified wins. - opts = self.p.parse_args(['--os-test-other', val2, - '--os-test-opt', val1]) - self.assertEqual(val1, opts.os_test_opt) - - def test_deprecated_env_options(self): - val = uuid.uuid4().hex - - with mock.patch.dict('os.environ', {'OS_TEST_OTHER': val}): - TesterPlugin.register_argparse_arguments(self.p) - - opts = self.p.parse_args([]) - self.assertEqual(val, opts.os_test_opt) - - def test_deprecated_env_multi_options(self): - val1 = uuid.uuid4().hex - val2 = uuid.uuid4().hex - - with mock.patch.dict('os.environ', {'OS_TEST_OPT': val1, - 'OS_TEST_OTHER': val2}): - TesterPlugin.register_argparse_arguments(self.p) - - opts = self.p.parse_args([]) - self.assertEqual(val1, opts.os_test_opt) diff --git a/keystoneclient/tests/unit/auth/test_conf.py b/keystoneclient/tests/unit/auth/test_conf.py deleted file mode 100644 index 47bf7590..00000000 --- a/keystoneclient/tests/unit/auth/test_conf.py +++ /dev/null @@ -1,178 +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. - -import uuid - -import mock -from oslo_config import cfg -from oslo_config import fixture as config -import stevedore - -from keystoneclient.auth import base -from keystoneclient.auth import conf -from keystoneclient.auth.identity import v2 as v2_auth -from keystoneclient.auth.identity import v3 as v3_auth -from keystoneclient import exceptions -from keystoneclient.tests.unit.auth import utils - - -class ConfTests(utils.TestCase): - - def setUp(self): - super(ConfTests, self).setUp() - self.deprecations.expect_deprecations() - self.conf_fixture = self.useFixture(config.Config()) - - # NOTE(jamielennox): we register the basic config options first because - # we need them in place before we can stub them. We will need to run - # the register again after we stub the auth section and auth plugin so - # it can load the plugin specific options. - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - def test_loading_v2(self): - section = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - trust_id = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(v2_auth.Password.get_options(), - group=section) - - self.conf_fixture.config(auth_plugin=self.V2PASS, - username=username, - password=password, - trust_id=trust_id, - tenant_id=tenant_id, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - self.assertEqual(trust_id, a.trust_id) - self.assertEqual(tenant_id, a.tenant_id) - - def test_loading_v3(self): - section = uuid.uuid4().hex - token = uuid.uuid4().hex - trust_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - project_domain_name = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(v3_auth.Token.get_options(), - group=section) - - self.conf_fixture.config(auth_plugin=self.V3TOKEN, - token=token, - trust_id=trust_id, - project_id=project_id, - project_domain_name=project_domain_name, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - - self.assertEqual(token, a.auth_methods[0].token) - self.assertEqual(trust_id, a.trust_id) - self.assertEqual(project_id, a.project_id) - self.assertEqual(project_domain_name, a.project_domain_name) - - def test_loading_invalid_plugin(self): - auth_plugin = uuid.uuid4().hex - self.conf_fixture.config(auth_plugin=auth_plugin, - group=self.GROUP) - - e = self.assertRaises(exceptions.NoMatchingPlugin, - conf.load_from_conf_options, - self.conf_fixture.conf, - self.GROUP) - - self.assertEqual(auth_plugin, e.name) - - def test_loading_with_no_data(self): - self.assertIsNone(conf.load_from_conf_options(self.conf_fixture.conf, - self.GROUP)) - - @mock.patch('stevedore.DriverManager') - def test_other_params(self, m): - m.return_value = utils.MockManager(utils.MockPlugin) - driver_name = uuid.uuid4().hex - - self.conf_fixture.register_opts(utils.MockPlugin.get_options(), - group=self.GROUP) - self.conf_fixture.config(auth_plugin=driver_name, - group=self.GROUP, - **self.TEST_VALS) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertTestVals(a) - - m.assert_called_once_with(namespace=base.PLUGIN_NAMESPACE, - name=driver_name, - invoke_on_load=False) - - @utils.mock_plugin - def test_same_section(self, m): - self.conf_fixture.register_opts(utils.MockPlugin.get_options(), - group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - self.conf_fixture.config(auth_plugin=uuid.uuid4().hex, - group=self.GROUP, - **self.TEST_VALS) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertTestVals(a) - - @utils.mock_plugin - def test_diff_section(self, m): - section = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(utils.MockPlugin.get_options(), - group=section) - self.conf_fixture.config(group=section, - auth_plugin=uuid.uuid4().hex, - **self.TEST_VALS) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertTestVals(a) - - def test_plugins_are_all_opts(self): - manager = stevedore.ExtensionManager(base.PLUGIN_NAMESPACE, - invoke_on_load=False, - propagate_map_exceptions=True) - - def inner(driver): - for p in driver.plugin.get_options(): - self.assertIsInstance(p, cfg.Opt) - - manager.map(inner) - - def test_get_common(self): - opts = conf.get_common_conf_options() - for opt in opts: - self.assertIsInstance(opt, cfg.Opt) - self.assertEqual(2, len(opts)) - - def test_get_named(self): - loaded_opts = conf.get_plugin_options('v2password') - plugin_opts = v2_auth.Password.get_options() - - self.assertEqual(plugin_opts, loaded_opts) diff --git a/keystoneclient/tests/unit/auth/test_default_cli.py b/keystoneclient/tests/unit/auth/test_default_cli.py deleted file mode 100644 index cb4603dc..00000000 --- a/keystoneclient/tests/unit/auth/test_default_cli.py +++ /dev/null @@ -1,92 +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. - -import argparse -import uuid - -import mock - -from keystoneclient.auth.identity.generic import cli -from keystoneclient import exceptions -from keystoneclient.tests.unit import utils - - -class DefaultCliTests(utils.TestCase): - - def setUp(self): - super(DefaultCliTests, self).setUp() - self.deprecations.expect_deprecations() - - def new_plugin(self, argv): - parser = argparse.ArgumentParser() - cli.DefaultCLI.register_argparse_arguments(parser) - opts = parser.parse_args(argv) - return cli.DefaultCLI.load_from_argparse_arguments(opts) - - def test_endpoint_override(self): - password = uuid.uuid4().hex - url = uuid.uuid4().hex - - p = self.new_plugin(['--os-auth-url', 'url', - '--os-endpoint', url, - '--os-password', password]) - - self.assertEqual(url, p.get_endpoint(None)) - self.assertEqual(password, p._password) - - def test_token_only_override(self): - self.assertRaises(exceptions.CommandError, - self.new_plugin, - ['--os-token', uuid.uuid4().hex]) - - def test_token_endpoint_override(self): - token = uuid.uuid4().hex - endpoint = uuid.uuid4().hex - - p = self.new_plugin(['--os-endpoint', endpoint, - '--os-token', token]) - - self.assertEqual(endpoint, p.get_endpoint(None)) - self.assertEqual(token, p.get_token(None)) - - def test_no_auth_url(self): - exc = self.assertRaises(exceptions.CommandError, - self.new_plugin, - ['--os-username', uuid.uuid4().hex]) - - self.assertIn('auth-url', str(exc)) - - @mock.patch('sys.stdin', autospec=True) - @mock.patch('getpass.getpass') - def test_prompt_password(self, mock_getpass, mock_stdin): - password = uuid.uuid4().hex - - mock_stdin.isatty = lambda: True - mock_getpass.return_value = password - - p = self.new_plugin(['--os-auth-url', uuid.uuid4().hex, - '--os-username', uuid.uuid4().hex]) - - self.assertEqual(password, p._password) - - @mock.patch('sys.stdin', autospec=True) - @mock.patch('getpass.getpass') - def test_prompt_no_password(self, mock_getpass, mock_stdin): - mock_stdin.isatty = lambda: True - mock_getpass.return_value = '' - - exc = self.assertRaises(exceptions.CommandError, - self.new_plugin, - ['--os-auth-url', uuid.uuid4().hex, - '--os-username', uuid.uuid4().hex]) - - self.assertIn('password', str(exc)) diff --git a/keystoneclient/tests/unit/auth/test_identity_common.py b/keystoneclient/tests/unit/auth/test_identity_common.py deleted file mode 100644 index be8a062d..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_common.py +++ /dev/null @@ -1,505 +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. - -import abc -import datetime -import uuid - -from keystoneauth1 import fixture -from keystoneauth1 import plugin -import mock -from oslo_utils import timeutils -import six - -from keystoneclient import access -from keystoneclient.auth import base -from keystoneclient.auth import identity -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -@six.add_metaclass(abc.ABCMeta) -class CommonIdentityTests(object): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - - TEST_COMPUTE_PUBLIC = 'http://nova/novapi/public' - TEST_COMPUTE_INTERNAL = 'http://nova/novapi/internal' - TEST_COMPUTE_ADMIN = 'http://nova/novapi/admin' - - TEST_PASS = uuid.uuid4().hex - - def setUp(self): - super(CommonIdentityTests, self).setUp() - self.deprecations.expect_deprecations() - - self.TEST_URL = '%s%s' % (self.TEST_ROOT_URL, self.version) - self.TEST_ADMIN_URL = '%s%s' % (self.TEST_ROOT_ADMIN_URL, self.version) - self.TEST_DISCOVERY = fixture.DiscoveryList(href=self.TEST_ROOT_URL) - - self.stub_auth_data() - - @abc.abstractmethod - def create_auth_plugin(self, **kwargs): - """Create an auth plugin that makes sense for the auth data. - - It doesn't really matter what auth mechanism is used but it should be - appropriate to the API version. - """ - pass - - @abc.abstractmethod - def get_auth_data(self, **kwargs): - """Return fake authentication data. - - This should register a valid token response and ensure that the compute - endpoints are set to TEST_COMPUTE_PUBLIC, _INTERNAL and _ADMIN. - """ - pass - - def stub_auth_data(self, **kwargs): - token = self.get_auth_data(**kwargs) - self.user_id = token.user_id - - try: - self.project_id = token.project_id - except AttributeError: - self.project_id = token.tenant_id - - self.stub_auth(json=token) - - @abc.abstractproperty - def version(self): - """The API version being tested.""" - - def test_discovering(self): - self.stub_url('GET', [], - base_url=self.TEST_COMPUTE_ADMIN, - json=self.TEST_DISCOVERY) - - body = 'SUCCESS' - - # which gives our sample values - self.stub_url('GET', ['path'], text=body) - - a = self.create_auth_plugin() - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - new_body = 'SC SUCCESS' - # if we don't specify a version, we use the URL from the SC - self.stub_url('GET', ['path'], - base_url=self.TEST_COMPUTE_ADMIN, - text=new_body) - - resp = s.get('/path', endpoint_filter={'service_type': 'compute', - 'interface': 'admin'}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(new_body, resp.text) - - def test_discovery_uses_session_cache(self): - # register responses such that if the discovery URL is hit more than - # once then the response will be invalid and not point to COMPUTE_ADMIN - resps = [{'json': self.TEST_DISCOVERY}, {'status_code': 500}] - self.requests_mock.get(self.TEST_COMPUTE_ADMIN, resps) - - body = 'SUCCESS' - self.stub_url('GET', ['path'], text=body) - - # now either of the two plugins I use, it should not cause a second - # request to the discovery url. - s = session.Session() - a = self.create_auth_plugin() - b = self.create_auth_plugin() - - for auth in (a, b): - resp = s.get('/path', - auth=auth, - endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - def test_discovery_uses_plugin_cache(self): - # register responses such that if the discovery URL is hit more than - # once then the response will be invalid and not point to COMPUTE_ADMIN - resps = [{'json': self.TEST_DISCOVERY}, {'status_code': 500}] - self.requests_mock.get(self.TEST_COMPUTE_ADMIN, resps) - - body = 'SUCCESS' - self.stub_url('GET', ['path'], text=body) - - # now either of the two sessions I use, it should not cause a second - # request to the discovery url. - sa = session.Session() - sb = session.Session() - auth = self.create_auth_plugin() - - for sess in (sa, sb): - resp = sess.get('/path', - auth=auth, - endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - def test_discovering_with_no_data(self): - # which returns discovery information pointing to TEST_URL but there is - # no data there. - self.stub_url('GET', [], - base_url=self.TEST_COMPUTE_ADMIN, - status_code=400) - - # so the url that will be used is the same TEST_COMPUTE_ADMIN - body = 'SUCCESS' - self.stub_url('GET', ['path'], base_url=self.TEST_COMPUTE_ADMIN, - text=body, status_code=200) - - a = self.create_auth_plugin() - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - def test_asking_for_auth_endpoint_ignores_checks(self): - a = self.create_auth_plugin() - s = session.Session(auth=a) - - auth_url = s.get_endpoint(service_type='compute', - interface=plugin.AUTH_INTERFACE) - - self.assertEqual(self.TEST_URL, auth_url) - - def _create_expired_auth_plugin(self, **kwargs): - expires = timeutils.utcnow() - datetime.timedelta(minutes=20) - expired_token = self.get_auth_data(expires=expires) - expired_auth_ref = access.AccessInfo.factory(body=expired_token) - - body = 'SUCCESS' - self.stub_url('GET', ['path'], - base_url=self.TEST_COMPUTE_ADMIN, text=body) - - a = self.create_auth_plugin(**kwargs) - a.auth_ref = expired_auth_ref - return a - - def test_reauthenticate(self): - a = self._create_expired_auth_plugin() - expired_auth_ref = a.auth_ref - s = session.Session(auth=a) - self.assertIsNot(expired_auth_ref, a.get_access(s)) - - def test_no_reauthenticate(self): - a = self._create_expired_auth_plugin(reauthenticate=False) - expired_auth_ref = a.auth_ref - s = session.Session(auth=a) - self.assertIs(expired_auth_ref, a.get_access(s)) - - def test_invalidate(self): - a = self.create_auth_plugin() - s = session.Session(auth=a) - - # trigger token fetching - s.get_auth_headers() - - self.assertTrue(a.auth_ref) - self.assertTrue(a.invalidate()) - self.assertIsNone(a.auth_ref) - self.assertFalse(a.invalidate()) - - def test_get_auth_properties(self): - a = self.create_auth_plugin() - s = session.Session() - - self.assertEqual(self.user_id, a.get_user_id(s)) - self.assertEqual(self.project_id, a.get_project_id(s)) - - -class V3(CommonIdentityTests, utils.TestCase): - - @property - def version(self): - return 'v3' - - def get_auth_data(self, **kwargs): - token = fixture.V3Token(**kwargs) - region = 'RegionOne' - - svc = token.add_service('identity') - svc.add_standard_endpoints(admin=self.TEST_ADMIN_URL, region=region) - - svc = token.add_service('compute') - svc.add_standard_endpoints(admin=self.TEST_COMPUTE_ADMIN, - public=self.TEST_COMPUTE_PUBLIC, - internal=self.TEST_COMPUTE_INTERNAL, - region=region) - - return token - - def stub_auth(self, subject_token=None, **kwargs): - if not subject_token: - subject_token = self.TEST_TOKEN - - kwargs.setdefault('headers', {})['X-Subject-Token'] = subject_token - self.stub_url('POST', ['auth', 'tokens'], **kwargs) - - def create_auth_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.TEST_URL) - kwargs.setdefault('username', self.TEST_USER) - kwargs.setdefault('password', self.TEST_PASS) - return identity.V3Password(**kwargs) - - -class V2(CommonIdentityTests, utils.TestCase): - - @property - def version(self): - return 'v2.0' - - def create_auth_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.TEST_URL) - kwargs.setdefault('username', self.TEST_USER) - kwargs.setdefault('password', self.TEST_PASS) - return identity.V2Password(**kwargs) - - def get_auth_data(self, **kwargs): - token = fixture.V2Token(**kwargs) - region = 'RegionOne' - - svc = token.add_service('identity') - svc.add_endpoint(self.TEST_ADMIN_URL, region=region) - - svc = token.add_service('compute') - svc.add_endpoint(public=self.TEST_COMPUTE_PUBLIC, - internal=self.TEST_COMPUTE_INTERNAL, - admin=self.TEST_COMPUTE_ADMIN, - region=region) - - return token - - def stub_auth(self, **kwargs): - self.stub_url('POST', ['tokens'], **kwargs) - - -class CatalogHackTests(utils.TestCase): - - TEST_URL = 'http://keystone.server:5000/v2.0' - OTHER_URL = 'http://other.server:5000/path' - - IDENTITY = 'identity' - - BASE_URL = 'http://keystone.server:5000/' - V2_URL = BASE_URL + 'v2.0' - V3_URL = BASE_URL + 'v3' - - def setUp(self): - super(CatalogHackTests, self).setUp() - self.deprecations.expect_deprecations() - - def test_getting_endpoints(self): - disc = fixture.DiscoveryList(href=self.BASE_URL) - self.stub_url('GET', - ['/'], - base_url=self.BASE_URL, - json=disc) - - token = fixture.V2Token() - service = token.add_service(self.IDENTITY) - service.add_endpoint(public=self.V2_URL, - admin=self.V2_URL, - internal=self.V2_URL) - - self.stub_url('POST', - ['tokens'], - base_url=self.V2_URL, - json=token) - - v2_auth = identity.V2Password(self.V2_URL, - username=uuid.uuid4().hex, - password=uuid.uuid4().hex) - - sess = session.Session(auth=v2_auth) - - endpoint = sess.get_endpoint(service_type=self.IDENTITY, - interface='public', - version=(3, 0)) - - self.assertEqual(self.V3_URL, endpoint) - - def test_returns_original_when_discover_fails(self): - token = fixture.V2Token() - service = token.add_service(self.IDENTITY) - service.add_endpoint(public=self.V2_URL, - admin=self.V2_URL, - internal=self.V2_URL) - - self.stub_url('POST', - ['tokens'], - base_url=self.V2_URL, - json=token) - - self.stub_url('GET', [], base_url=self.BASE_URL, status_code=404) - - v2_auth = identity.V2Password(self.V2_URL, - username=uuid.uuid4().hex, - password=uuid.uuid4().hex) - - sess = session.Session(auth=v2_auth) - - endpoint = sess.get_endpoint(service_type=self.IDENTITY, - interface='public', - version=(3, 0)) - - self.assertEqual(self.V2_URL, endpoint) - - def test_getting_endpoints_on_auth_interface(self): - disc = fixture.DiscoveryList(href=self.BASE_URL) - self.stub_url('GET', - ['/'], - base_url=self.BASE_URL, - status_code=300, - json=disc) - - token = fixture.V2Token() - service = token.add_service(self.IDENTITY) - service.add_endpoint(public=self.V2_URL, - admin=self.V2_URL, - internal=self.V2_URL) - - self.stub_url('POST', - ['tokens'], - base_url=self.V2_URL, - json=token) - - v2_auth = identity.V2Password(self.V2_URL, - username=uuid.uuid4().hex, - password=uuid.uuid4().hex) - - sess = session.Session(auth=v2_auth) - - endpoint = sess.get_endpoint(interface=plugin.AUTH_INTERFACE, - version=(3, 0)) - - self.assertEqual(self.V3_URL, endpoint) - - -class GenericPlugin(base.BaseAuthPlugin): - - BAD_TOKEN = uuid.uuid4().hex - - def __init__(self): - super(GenericPlugin, self).__init__() - - self.endpoint = 'http://keystone.host:5000' - - self.headers = {'headerA': 'valueA', - 'headerB': 'valueB'} - - self.cert = '/path/to/cert' - self.connection_params = {'cert': self.cert, 'verify': False} - - def url(self, prefix): - return '%s/%s' % (self.endpoint, prefix) - - def get_token(self, session, **kwargs): - # NOTE(jamielennox): by specifying get_headers this should not be used - return self.BAD_TOKEN - - def get_headers(self, session, **kwargs): - return self.headers - - def get_endpoint(self, session, **kwargs): - return self.endpoint - - def get_connection_params(self, session, **kwargs): - return self.connection_params - - -class GenericAuthPluginTests(utils.TestCase): - - # filter doesn't matter to GenericPlugin, but we have to specify one - ENDPOINT_FILTER = {uuid.uuid4().hex: uuid.uuid4().hex} - - def setUp(self): - super(GenericAuthPluginTests, self).setUp() - self.auth = GenericPlugin() - - with self.deprecations.expect_deprecations_here(): - self.session = session.Session(auth=self.auth) - - def test_setting_headers(self): - text = uuid.uuid4().hex - self.stub_url('GET', base_url=self.auth.url('prefix'), text=text) - - resp = self.session.get('prefix', endpoint_filter=self.ENDPOINT_FILTER) - - self.assertEqual(text, resp.text) - - for k, v in self.auth.headers.items(): - self.assertRequestHeaderEqual(k, v) - - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(self.session.get_token()) - self.assertEqual(self.auth.headers, - self.session.get_auth_headers()) - self.assertNotIn('X-Auth-Token', - self.requests_mock.last_request.headers) - - def test_setting_connection_params(self): - text = uuid.uuid4().hex - - with mock.patch.object(self.session.session, 'request') as mocked: - mocked.return_value = utils.test_response(text=text) - resp = self.session.get('prefix', - endpoint_filter=self.ENDPOINT_FILTER) - - self.assertEqual(text, resp.text) - - # the cert and verify values passed to request are those that were - # returned from the auth plugin as connection params. - - mocked.assert_called_once_with('GET', - self.auth.url('prefix'), - headers=mock.ANY, - allow_redirects=False, - cert=self.auth.cert, - verify=False) - - def test_setting_bad_connection_params(self): - # The uuid name parameter here is unknown and not in the allowed params - # to be returned to the session and so an error will be raised. - name = uuid.uuid4().hex - self.auth.connection_params[name] = uuid.uuid4().hex - - e = self.assertRaises(exceptions.UnsupportedParameters, - self.session.get, - 'prefix', - endpoint_filter=self.ENDPOINT_FILTER) - - self.assertIn(name, str(e)) diff --git a/keystoneclient/tests/unit/auth/test_identity_v2.py b/keystoneclient/tests/unit/auth/test_identity_v2.py deleted file mode 100644 index 8ef87c43..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_v2.py +++ /dev/null @@ -1,328 +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. - -import argparse -import copy -import uuid - -import mock - -from keystoneclient.auth.identity import v2 -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class V2IdentityPlugin(utils.TestCase): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v2.0') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v2.0') - - TEST_PASS = 'password' - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "adminURL": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:8774/v1.0", - "publicURL": "http://cdn.admin-nets.local:8774/v1.0/" - }], - "type": "nova_compat", - "name": "nova_compat" - }, { - "endpoints": [{ - "adminURL": "http://nova/novapi/admin", - "region": "RegionOne", - "internalURL": "http://nova/novapi/internal", - "publicURL": "http://nova/novapi/public" - }], - "type": "compute", - "name": "nova" - }, { - "endpoints": [{ - "adminURL": "http://glance/glanceapi/admin", - "region": "RegionOne", - "internalURL": "http://glance/glanceapi/internal", - "publicURL": "http://glance/glanceapi/public" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "adminURL": TEST_ADMIN_URL, - "region": "RegionOne", - "internalURL": "http://127.0.0.1:5000/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - }], - "type": "identity", - "name": "keystone" - }, { - "endpoints": [{ - "adminURL": "http://swift/swiftapi/admin", - "region": "RegionOne", - "internalURL": "http://swift/swiftapi/internal", - "publicURL": "http://swift/swiftapi/public" - }], - "type": "object-store", - "name": "swift" - }] - - def setUp(self): - super(V2IdentityPlugin, self).setUp() - self.deprecations.expect_deprecations() - self.TEST_RESPONSE_DICT = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10.000123Z", - "id": self.TEST_TOKEN, - "tenant": { - "id": self.TEST_TENANT_ID - }, - }, - "user": { - "id": self.TEST_USER - }, - "serviceCatalog": self.TEST_SERVICE_CATALOG, - }, - } - - def stub_auth(self, **kwargs): - self.stub_url('POST', ['tokens'], **kwargs) - - def test_authenticate_with_username_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - self.assertIsNone(a.user_id) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'username': self.TEST_USER, - 'password': self.TEST_PASS}}} - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_user_id_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, user_id=self.TEST_USER, - password=self.TEST_PASS) - self.assertIsNone(a.username) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'userId': self.TEST_USER, - 'password': self.TEST_PASS}}} - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_username_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, tenant_id=self.TEST_TENANT_ID) - self.assertIsNone(a.user_id) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'username': self.TEST_USER, - 'password': self.TEST_PASS}, - 'tenantId': self.TEST_TENANT_ID}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_user_id_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, user_id=self.TEST_USER, - password=self.TEST_PASS, tenant_id=self.TEST_TENANT_ID) - self.assertIsNone(a.username) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'userId': self.TEST_USER, - 'password': self.TEST_PASS}, - 'tenantId': self.TEST_TENANT_ID}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_token(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Token(self.TEST_URL, 'foo') - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'token': {'id': 'foo'}}} - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('x-Auth-Token', 'foo') - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_trust_id(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, trust_id='trust') - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'username': self.TEST_USER, - 'password': self.TEST_PASS}, - 'trust_id': 'trust'}} - - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def _do_service_url_test(self, base_url, endpoint_filter): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', ['path'], - base_url=base_url, - text='SUCCESS', status_code=200) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter=endpoint_filter) - - self.assertEqual(resp.status_code, 200) - self.assertEqual(self.requests_mock.last_request.url, - base_url + '/path') - - def test_service_url(self): - endpoint_filter = {'service_type': 'compute', - 'interface': 'admin', - 'service_name': 'nova'} - self._do_service_url_test('http://nova/novapi/admin', endpoint_filter) - - def test_service_url_defaults_to_public(self): - endpoint_filter = {'service_type': 'compute'} - self._do_service_url_test('http://nova/novapi/public', endpoint_filter) - - def test_endpoint_filter_without_service_type_fails(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.EndpointNotFound, s.get, '/path', - endpoint_filter={'interface': 'admin'}) - - def test_full_url_overrides_endpoint_filter(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [], - base_url='http://testurl/', - text='SUCCESS', status_code=200) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('http://testurl/', - endpoint_filter={'service_type': 'compute'}) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.text, 'SUCCESS') - - def test_invalid_auth_response_dict(self): - self.stub_auth(json={'hello': 'world'}) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalid_auth_response_type(self): - self.stub_url('POST', ['tokens'], text='testdata') - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalidate_response(self): - resp_data1 = copy.deepcopy(self.TEST_RESPONSE_DICT) - resp_data2 = copy.deepcopy(self.TEST_RESPONSE_DICT) - - resp_data1['access']['token']['id'] = 'token1' - resp_data2['access']['token']['id'] = 'token2' - - auth_responses = [{'json': resp_data1}, {'json': resp_data2}] - self.stub_auth(response_list=auth_responses) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token1', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token1'}, s.get_auth_headers()) - - a.invalidate() - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token2', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token2'}, s.get_auth_headers()) - - def test_doesnt_log_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - password = uuid.uuid4().hex - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=password) - s = session.Session(auth=a) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(self.TEST_TOKEN, s.get_token()) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - self.assertNotIn(password, self.logger.output) - - def test_password_with_no_user_id_or_name(self): - self.assertRaises(TypeError, - v2.Password, self.TEST_URL, password=self.TEST_PASS) - - @mock.patch('sys.stdin', autospec=True) - def test_prompt_password(self, mock_stdin): - parser = argparse.ArgumentParser() - v2.Password.register_argparse_arguments(parser) - - username = uuid.uuid4().hex - auth_url = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - password = uuid.uuid4().hex - - opts = parser.parse_args(['--os-username', username, - '--os-auth-url', auth_url, - '--os-tenant-id', tenant_id]) - - with mock.patch('getpass.getpass') as mock_getpass: - mock_getpass.return_value = password - mock_stdin.isatty = lambda: True - - plugin = v2.Password.load_from_argparse_arguments(opts) - - self.assertEqual(auth_url, plugin.auth_url) - self.assertEqual(username, plugin.username) - self.assertEqual(tenant_id, plugin.tenant_id) - self.assertEqual(password, plugin.password) diff --git a/keystoneclient/tests/unit/auth/test_identity_v3.py b/keystoneclient/tests/unit/auth/test_identity_v3.py deleted file mode 100644 index 534e9974..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_v3.py +++ /dev/null @@ -1,570 +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. - -import argparse -import copy -import uuid - -from keystoneauth1 import fixture -import mock - -from keystoneclient import access -from keystoneclient.auth.identity import v3 -from keystoneclient.auth.identity.v3 import base as v3_base -from keystoneclient import client -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class V3IdentityPlugin(utils.TestCase): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v3') - - TEST_PASS = 'password' - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "url": "http://cdn.admin-nets.local:8774/v1.0/", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:8774/v1.0", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "interface": "admin" - }], - "type": "nova_compat" - }, { - "endpoints": [{ - "url": "http://nova/novapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://nova/novapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://nova/novapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "compute", - "name": "nova", - }, { - "endpoints": [{ - "url": "http://glance/glanceapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://glance/glanceapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://glance/glanceapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "internal" - }, { - "url": TEST_ADMIN_URL, - "region": "RegionOne", - "interface": "admin" - }], - "type": "identity" - }, { - "endpoints": [{ - "url": "http://swift/swiftapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://swift/swiftapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://swift/swiftapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "object-store" - }] - - def setUp(self): - super(V3IdentityPlugin, self).setUp() - - self.TEST_DISCOVERY_RESPONSE = { - 'versions': {'values': [fixture.V3Discovery(self.TEST_URL)]}} - - self.deprecations.expect_deprecations() - - self.TEST_RESPONSE_DICT = { - "token": { - "methods": [ - "token", - "password" - ], - - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_TENANT_ID, - "name": self.TEST_TENANT_NAME - }, - "user": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_USER, - "name": self.TEST_USER - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": self.TEST_SERVICE_CATALOG - }, - } - self.TEST_PROJECTS_RESPONSE = { - "projects": [ - { - "domain_id": "1789d1", - "enabled": "True", - "id": "263fd9", - "links": { - "self": "https://identity:5000/v3/projects/263fd9" - }, - "name": "Dev Group A" - }, - { - "domain_id": "1789d1", - "enabled": "True", - "id": "e56ad3", - "links": { - "self": "https://identity:5000/v3/projects/e56ad3" - }, - "name": "Dev Group B" - } - ], - "links": { - "self": "https://identity:5000/v3/projects", - } - } - - def stub_auth(self, subject_token=None, **kwargs): - if not subject_token: - subject_token = self.TEST_TOKEN - - self.stub_url('POST', ['auth', 'tokens'], - headers={'X-Subject-Token': subject_token}, **kwargs) - - def test_authenticate_with_username_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}}} - - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_username_password_unscoped(self): - del self.TEST_RESPONSE_DICT['token']['catalog'] - del self.TEST_RESPONSE_DICT['token']['project'] - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url(method="GET", json=self.TEST_DISCOVERY_RESPONSE) - test_user_id = self.TEST_RESPONSE_DICT['token']['user']['id'] - self.stub_url(method="GET", - json=self.TEST_PROJECTS_RESPONSE, - parts=['users', test_user_id, 'projects']) - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - cs = client.Client(session=s) - - # As a sanity check on the auth_ref, make sure client has the - # proper user id, that it fetches the right project response - self.assertEqual(test_user_id, a.auth_ref.user_id) - t = cs.projects.list(user=a.auth_ref.user_id) - self.assertEqual(2, len(t)) - - def test_authenticate_with_username_password_domain_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, domain_id=self.TEST_DOMAIN_ID) - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}, - 'scope': {'domain': {'id': self.TEST_DOMAIN_ID}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_username_password_project_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, - project_id=self.TEST_TENANT_ID) - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}, - 'scope': {'project': {'id': self.TEST_TENANT_ID}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - self.assertEqual(s.auth.auth_ref.project_id, self.TEST_TENANT_ID) - - def test_authenticate_with_token(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['token'], - 'token': {'id': self.TEST_TOKEN}}}} - - self.assertRequestBodyIs(json=req) - - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_expired(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - d = copy.deepcopy(self.TEST_RESPONSE_DICT) - d['token']['expires_at'] = '2000-01-01T00:00:10.000123Z' - - a = v3.Password(self.TEST_URL, username='username', - password='password') - a.auth_ref = access.AccessInfo.factory(body=d) - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - self.assertEqual(a.auth_ref['expires_at'], - self.TEST_RESPONSE_DICT['token']['expires_at']) - - def test_with_domain_and_project_scoping(self): - a = v3.Password(self.TEST_URL, username='username', - password='password', project_id='project', - domain_id='domain') - - self.assertRaises(exceptions.AuthorizationFailure, - a.get_token, None) - self.assertRaises(exceptions.AuthorizationFailure, - a.get_headers, None) - - def test_with_trust_id(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, trust_id='trust') - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}, - 'scope': {'OS-TRUST:trust': {'id': 'trust'}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_multiple_mechanisms_factory(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - p = v3.PasswordMethod(username=self.TEST_USER, password=self.TEST_PASS) - t = v3.TokenMethod(token='foo') - a = v3.Auth(self.TEST_URL, [p, t], trust_id='trust') - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password', 'token'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}, - 'token': {'id': 'foo'}}, - 'scope': {'OS-TRUST:trust': {'id': 'trust'}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_multiple_mechanisms(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - p = v3.PasswordMethod(username=self.TEST_USER, - password=self.TEST_PASS) - t = v3.TokenMethod(token='foo') - a = v3.Auth(self.TEST_URL, [p, t], trust_id='trust') - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password', 'token'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}, - 'token': {'id': 'foo'}}, - 'scope': {'OS-TRUST:trust': {'id': 'trust'}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_multiple_scopes(self): - s = session.Session() - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, password=self.TEST_PASS, - domain_id='x', project_id='x') - self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s) - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, password=self.TEST_PASS, - domain_id='x', trust_id='x') - self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s) - - def _do_service_url_test(self, base_url, endpoint_filter): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', ['path'], - base_url=base_url, - text='SUCCESS', status_code=200) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter=endpoint_filter) - - self.assertEqual(resp.status_code, 200) - self.assertEqual(self.requests_mock.last_request.url, - base_url + '/path') - - def test_service_url(self): - endpoint_filter = {'service_type': 'compute', - 'interface': 'admin', - 'service_name': 'nova'} - self._do_service_url_test('http://nova/novapi/admin', endpoint_filter) - - def test_service_url_defaults_to_public(self): - endpoint_filter = {'service_type': 'compute'} - self._do_service_url_test('http://nova/novapi/public', endpoint_filter) - - def test_endpoint_filter_without_service_type_fails(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.EndpointNotFound, s.get, '/path', - endpoint_filter={'interface': 'admin'}) - - def test_full_url_overrides_endpoint_filter(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [], - base_url='http://testurl/', - text='SUCCESS', status_code=200) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('http://testurl/', - endpoint_filter={'service_type': 'compute'}) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.text, 'SUCCESS') - - def test_invalid_auth_response_dict(self): - self.stub_auth(json={'hello': 'world'}) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalid_auth_response_type(self): - self.stub_url('POST', ['auth', 'tokens'], text='testdata') - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalidate_response(self): - auth_responses = [{'status_code': 200, 'json': self.TEST_RESPONSE_DICT, - 'headers': {'X-Subject-Token': 'token1'}}, - {'status_code': 200, 'json': self.TEST_RESPONSE_DICT, - 'headers': {'X-Subject-Token': 'token2'}}] - - self.requests_mock.post('%s/auth/tokens' % self.TEST_URL, - auth_responses) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token1', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token1'}, s.get_auth_headers()) - a.invalidate() - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token2', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token2'}, s.get_auth_headers()) - - def test_doesnt_log_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - password = uuid.uuid4().hex - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=password) - s = session.Session(a) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(self.TEST_TOKEN, s.get_token()) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - self.assertNotIn(password, self.logger.output) - - def test_sends_nocatalog(self): - del self.TEST_RESPONSE_DICT['token']['catalog'] - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS, - include_catalog=False) - s = session.Session(auth=a) - - s.get_auth_headers() - - auth_url = self.TEST_URL + '/auth/tokens' - self.assertEqual(auth_url, a.token_url) - self.assertEqual(auth_url + '?nocatalog', - self.requests_mock.last_request.url) - - def test_symbols(self): - self.assertIs(v3.AuthMethod, v3_base.AuthMethod) - self.assertIs(v3.AuthConstructor, v3_base.AuthConstructor) - self.assertIs(v3.Auth, v3_base.Auth) - - def test_unscoped_request(self): - token = fixture.V3Token() - self.stub_auth(json=token) - password = uuid.uuid4().hex - - a = v3.Password(self.TEST_URL, - user_id=token.user_id, - password=password, - unscoped=True) - s = session.Session() - - auth_ref = a.get_access(s) - - with self.deprecations.expect_deprecations_here(): - self.assertFalse(auth_ref.scoped) - body = self.requests_mock.last_request.json() - - ident = body['auth']['identity'] - - self.assertEqual(['password'], ident['methods']) - self.assertEqual(token.user_id, ident['password']['user']['id']) - self.assertEqual(password, ident['password']['user']['password']) - - self.assertEqual({}, body['auth']['scope']['unscoped']) - - def test_unscoped_with_scope_data(self): - a = v3.Password(self.TEST_URL, - user_id=uuid.uuid4().hex, - password=uuid.uuid4().hex, - unscoped=True, - project_id=uuid.uuid4().hex) - - s = session.Session() - - self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s) - - @mock.patch('sys.stdin', autospec=True) - def test_prompt_password(self, mock_stdin): - parser = argparse.ArgumentParser() - v3.Password.register_argparse_arguments(parser) - - username = uuid.uuid4().hex - user_domain_id = uuid.uuid4().hex - auth_url = uuid.uuid4().hex - project_id = uuid.uuid4().hex - password = uuid.uuid4().hex - - opts = parser.parse_args(['--os-username', username, - '--os-auth-url', auth_url, - '--os-user-domain-id', user_domain_id, - '--os-project-id', project_id]) - - with mock.patch('getpass.getpass') as mock_getpass: - mock_getpass.return_value = password - mock_stdin.isatty = lambda: True - - plugin = v3.Password.load_from_argparse_arguments(opts) - - self.assertEqual(auth_url, plugin.auth_url) - self.assertEqual(username, plugin.auth_methods[0].username) - self.assertEqual(project_id, plugin.project_id) - self.assertEqual(user_domain_id, - plugin.auth_methods[0].user_domain_id) - self.assertEqual(password, plugin.auth_methods[0].password) diff --git a/keystoneclient/tests/unit/auth/test_identity_v3_federated.py b/keystoneclient/tests/unit/auth/test_identity_v3_federated.py deleted file mode 100644 index 7cbb5ab1..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_v3_federated.py +++ /dev/null @@ -1,99 +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. - -import copy -import uuid - -from keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient.auth.identity import v3 -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class TesterFederationPlugin(v3.FederatedBaseAuth): - - def get_unscoped_auth_ref(self, sess, **kwargs): - # This would go and talk to an idp or something - resp = sess.post(self.federated_token_url, authenticated=False) - return access.AccessInfo.factory(resp=resp, body=resp.json()) - - -class V3FederatedPlugin(utils.TestCase): - - AUTH_URL = 'http://keystone/v3' - - def setUp(self): - super(V3FederatedPlugin, self).setUp() - - self.deprecations.expect_deprecations() - - self.unscoped_token = fixture.V3Token() - self.unscoped_token_id = uuid.uuid4().hex - self.scoped_token = copy.deepcopy(self.unscoped_token) - self.scoped_token.set_project_scope() - self.scoped_token.methods.append('token') - self.scoped_token_id = uuid.uuid4().hex - - s = self.scoped_token.add_service('compute', name='nova') - s.add_standard_endpoints(public='http://nova/public', - admin='http://nova/admin', - internal='http://nova/internal') - - self.idp = uuid.uuid4().hex - self.protocol = uuid.uuid4().hex - - self.token_url = ('%s/OS-FEDERATION/identity_providers/%s/protocols/%s' - '/auth' % (self.AUTH_URL, self.idp, self.protocol)) - - headers = {'X-Subject-Token': self.unscoped_token_id} - self.unscoped_mock = self.requests_mock.post(self.token_url, - json=self.unscoped_token, - headers=headers) - - headers = {'X-Subject-Token': self.scoped_token_id} - auth_url = self.AUTH_URL + '/auth/tokens' - self.scoped_mock = self.requests_mock.post(auth_url, - json=self.scoped_token, - headers=headers) - - def get_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.AUTH_URL) - kwargs.setdefault('protocol', self.protocol) - kwargs.setdefault('identity_provider', self.idp) - return TesterFederationPlugin(**kwargs) - - def test_federated_url(self): - plugin = self.get_plugin() - self.assertEqual(self.token_url, plugin.federated_token_url) - - def test_unscoped_behaviour(self): - sess = session.Session(auth=self.get_plugin()) - self.assertEqual(self.unscoped_token_id, sess.get_token()) - - self.assertTrue(self.unscoped_mock.called) - self.assertFalse(self.scoped_mock.called) - - def test_scoped_behaviour(self): - auth = self.get_plugin(project_id=self.scoped_token.project_id) - sess = session.Session(auth=auth) - self.assertEqual(self.scoped_token_id, sess.get_token()) - - self.assertTrue(self.unscoped_mock.called) - self.assertTrue(self.scoped_mock.called) - - def test_options(self): - opts = [o.name for o in v3.FederatedBaseAuth.get_options()] - - self.assertIn('protocol', opts) - self.assertIn('identity-provider', opts) diff --git a/keystoneclient/tests/unit/auth/test_loading.py b/keystoneclient/tests/unit/auth/test_loading.py deleted file mode 100644 index 3c2689dd..00000000 --- a/keystoneclient/tests/unit/auth/test_loading.py +++ /dev/null @@ -1,46 +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. - -import uuid - - -from keystoneclient.tests.unit.auth import utils - - -class TestOtherLoading(utils.TestCase): - - def test_loading_getter(self): - - called_opts = [] - - vals = {'a-int': 44, - 'a-bool': False, - 'a-float': 99.99, - 'a-str': 'value'} - - val = uuid.uuid4().hex - - def _getter(opt): - called_opts.append(opt.name) - # return str because oslo.config should convert them back - return str(vals[opt.name]) - - p = utils.MockPlugin.load_from_options_getter(_getter, other=val) - - self.assertEqual(set(vals), set(called_opts)) - - for k, v in vals.items(): - # replace - to _ because it's the dest used to create kwargs - self.assertEqual(v, p[k.replace('-', '_')]) - - # check that additional kwargs get passed through - self.assertEqual(val, p['other']) diff --git a/keystoneclient/tests/unit/auth/test_password.py b/keystoneclient/tests/unit/auth/test_password.py deleted file mode 100644 index 020eb124..00000000 --- a/keystoneclient/tests/unit/auth/test_password.py +++ /dev/null @@ -1,99 +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. - -import argparse -import uuid - -import mock - -from keystoneclient.auth.identity.generic import password -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 -from keystoneclient.auth.identity.v3 import password as v3_password -from keystoneclient.tests.unit.auth import utils - - -class PasswordTests(utils.GenericPluginTestCase): - - PLUGIN_CLASS = password.Password - V2_PLUGIN_CLASS = v2.Password - V3_PLUGIN_CLASS = v3.Password - - def new_plugin(self, **kwargs): - kwargs.setdefault('username', uuid.uuid4().hex) - kwargs.setdefault('password', uuid.uuid4().hex) - return super(PasswordTests, self).new_plugin(**kwargs) - - def test_with_user_domain_params(self): - self.stub_discovery() - - self.assertCreateV3(domain_id=uuid.uuid4().hex, - user_domain_id=uuid.uuid4().hex) - - def test_v3_user_params_v2_url(self): - self.stub_discovery(v3=False) - self.assertDiscoveryFailure(user_domain_id=uuid.uuid4().hex) - - def test_options(self): - opts = [o.name for o in self.PLUGIN_CLASS.get_options()] - - allowed_opts = ['username', - 'user-domain-id', - 'user-domain-name', - 'user-id', - 'password', - - 'domain-id', - 'domain-name', - 'tenant-id', - 'tenant-name', - 'project-id', - 'project-name', - 'project-domain-id', - 'project-domain-name', - 'trust-id', - 'auth-url'] - - self.assertEqual(set(allowed_opts), set(opts)) - self.assertEqual(len(allowed_opts), len(opts)) - - def test_symbols(self): - self.assertIs(v3.Password, v3_password.Password) - self.assertIs(v3.PasswordMethod, v3_password.PasswordMethod) - - @mock.patch('sys.stdin', autospec=True) - def test_prompt_password(self, mock_stdin): - parser = argparse.ArgumentParser() - self.PLUGIN_CLASS.register_argparse_arguments(parser) - - username = uuid.uuid4().hex - user_domain_id = uuid.uuid4().hex - auth_url = uuid.uuid4().hex - project_id = uuid.uuid4().hex - password = uuid.uuid4().hex - - opts = parser.parse_args(['--os-username', username, - '--os-auth-url', auth_url, - '--os-user-domain-id', user_domain_id, - '--os-project-id', project_id]) - - with mock.patch('getpass.getpass') as mock_getpass: - mock_getpass.return_value = password - mock_stdin.isatty = lambda: True - - plugin = self.PLUGIN_CLASS.load_from_argparse_arguments(opts) - - self.assertEqual(auth_url, plugin.auth_url) - self.assertEqual(username, plugin._username) - self.assertEqual(project_id, plugin._project_id) - self.assertEqual(user_domain_id, plugin._user_domain_id) - self.assertEqual(password, plugin._password) diff --git a/keystoneclient/tests/unit/auth/test_token.py b/keystoneclient/tests/unit/auth/test_token.py deleted file mode 100644 index ce4c1cdc..00000000 --- a/keystoneclient/tests/unit/auth/test_token.py +++ /dev/null @@ -1,52 +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. - -import uuid - -from keystoneclient.auth.identity.generic import token -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 -from keystoneclient.auth.identity.v3 import token as v3_token -from keystoneclient.tests.unit.auth import utils - - -class TokenTests(utils.GenericPluginTestCase): - - PLUGIN_CLASS = token.Token - V2_PLUGIN_CLASS = v2.Token - V3_PLUGIN_CLASS = v3.Token - - def new_plugin(self, **kwargs): - kwargs.setdefault('token', uuid.uuid4().hex) - return super(TokenTests, self).new_plugin(**kwargs) - - def test_options(self): - opts = [o.name for o in self.PLUGIN_CLASS.get_options()] - - allowed_opts = ['token', - 'domain-id', - 'domain-name', - 'tenant-id', - 'tenant-name', - 'project-id', - 'project-name', - 'project-domain-id', - 'project-domain-name', - 'trust-id', - 'auth-url'] - - self.assertEqual(set(allowed_opts), set(opts)) - self.assertEqual(len(allowed_opts), len(opts)) - - def test_symbols(self): - self.assertIs(v3.Token, v3_token.Token) - self.assertIs(v3.TokenMethod, v3_token.TokenMethod) diff --git a/keystoneclient/tests/unit/auth/test_token_endpoint.py b/keystoneclient/tests/unit/auth/test_token_endpoint.py deleted file mode 100644 index 9a9a1ed9..00000000 --- a/keystoneclient/tests/unit/auth/test_token_endpoint.py +++ /dev/null @@ -1,67 +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 testtools import matchers - -from keystoneclient.auth import token_endpoint -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class TokenEndpointTest(utils.TestCase): - - TEST_TOKEN = 'aToken' - TEST_URL = 'http://server/prefix' - - def setUp(self): - super(TokenEndpointTest, self).setUp() - self.deprecations.expect_deprecations() - - def test_basic_case(self): - self.requests_mock.get(self.TEST_URL, text='body') - - a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session(auth=a) - - data = s.get(self.TEST_URL, authenticated=True) - - self.assertEqual(data.text, 'body') - self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) - - def test_basic_endpoint_case(self): - self.stub_url('GET', ['p'], text='body') - a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session(auth=a) - - data = s.get('/p', - authenticated=True, - endpoint_filter={'service': 'identity'}) - - self.assertEqual(self.TEST_URL, a.get_endpoint(s)) - self.assertEqual('body', data.text) - self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) - - def test_token_endpoint_options(self): - opt_names = [opt.name for opt in token_endpoint.Token.get_options()] - - self.assertThat(opt_names, matchers.HasLength(2)) - - self.assertIn('token', opt_names) - self.assertIn('endpoint', opt_names) - - def test_token_endpoint_user_id(self): - a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session() - - # we can't know this information about this sort of plugin - self.assertIsNone(a.get_user_id(s)) - self.assertIsNone(a.get_project_id(s)) diff --git a/keystoneclient/tests/unit/auth/utils.py b/keystoneclient/tests/unit/auth/utils.py deleted file mode 100644 index b6931728..00000000 --- a/keystoneclient/tests/unit/auth/utils.py +++ /dev/null @@ -1,202 +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. - -import functools -import uuid - -from keystoneauth1 import fixture -import mock -from oslo_config import cfg - -from keystoneclient import access -from keystoneclient.auth import base -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class MockPlugin(base.BaseAuthPlugin): - - INT_DESC = 'test int' - FLOAT_DESC = 'test float' - BOOL_DESC = 'test bool' - STR_DESC = 'test str' - STR_DEFAULT = uuid.uuid4().hex - - def __init__(self, **kwargs): - self._data = kwargs - - def __getitem__(self, key): - """Get the data of the key.""" - return self._data[key] - - def get_token(self, *args, **kwargs): - return 'aToken' - - def get_endpoint(self, *args, **kwargs): - return 'http://test' - - @classmethod - def get_options(cls): - return [ - cfg.IntOpt('a-int', default='3', help=cls.INT_DESC), - cfg.BoolOpt('a-bool', help=cls.BOOL_DESC), - cfg.FloatOpt('a-float', help=cls.FLOAT_DESC), - cfg.StrOpt('a-str', help=cls.STR_DESC, default=cls.STR_DEFAULT), - ] - - -class MockManager(object): - - def __init__(self, driver): - self.driver = driver - - -def mock_plugin(f): - @functools.wraps(f) - def inner(*args, **kwargs): - with mock.patch.object(base, 'get_plugin_class') as m: - m.return_value = MockPlugin - args = list(args) + [m] - return f(*args, **kwargs) - - return inner - - -class TestCase(utils.TestCase): - - GROUP = 'auth' - V2PASS = 'v2password' - V3TOKEN = 'v3token' - - a_int = 88 - a_float = 88.8 - a_bool = False - - TEST_VALS = {'a_int': a_int, - 'a_float': a_float, - 'a_bool': a_bool} - - def assertTestVals(self, plugin, vals=TEST_VALS): - for k, v in vals.items(): - self.assertEqual(v, plugin[k]) - - -class GenericPluginTestCase(utils.TestCase): - - TEST_URL = 'http://keystone.host:5000/' - - # OVERRIDE THESE IN SUB CLASSES - PLUGIN_CLASS = None - V2_PLUGIN_CLASS = None - V3_PLUGIN_CLASS = None - - def setUp(self): - super(GenericPluginTestCase, self).setUp() - - self.token_v2 = fixture.V2Token() - self.token_v3 = fixture.V3Token() - self.token_v3_id = uuid.uuid4().hex - - self.deprecations.expect_deprecations() - self.session = session.Session() - - self.stub_url('POST', ['v2.0', 'tokens'], json=self.token_v2) - self.stub_url('POST', ['v3', 'auth', 'tokens'], - headers={'X-Subject-Token': self.token_v3_id}, - json=self.token_v3) - - def new_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.TEST_URL) - return self.PLUGIN_CLASS(**kwargs) - - def stub_discovery(self, base_url=None, **kwargs): - kwargs.setdefault('href', self.TEST_URL) - disc = fixture.DiscoveryList(**kwargs) - self.stub_url('GET', json=disc, base_url=base_url, status_code=300) - return disc - - def assertCreateV3(self, **kwargs): - auth = self.new_plugin(**kwargs) - auth_ref = auth.get_auth_ref(self.session) - self.assertIsInstance(auth_ref, access.AccessInfoV3) - self.assertEqual(self.TEST_URL + 'v3/auth/tokens', - self.requests_mock.last_request.url) - self.assertIsInstance(auth._plugin, self.V3_PLUGIN_CLASS) - return auth - - def assertCreateV2(self, **kwargs): - auth = self.new_plugin(**kwargs) - auth_ref = auth.get_auth_ref(self.session) - self.assertIsInstance(auth_ref, access.AccessInfoV2) - self.assertEqual(self.TEST_URL + 'v2.0/tokens', - self.requests_mock.last_request.url) - self.assertIsInstance(auth._plugin, self.V2_PLUGIN_CLASS) - return auth - - def assertDiscoveryFailure(self, **kwargs): - plugin = self.new_plugin(**kwargs) - self.assertRaises(exceptions.DiscoveryFailure, - plugin.get_auth_ref, - self.session) - - def test_create_v3_if_domain_params(self): - self.stub_discovery() - - self.assertCreateV3(domain_id=uuid.uuid4().hex) - self.assertCreateV3(domain_name=uuid.uuid4().hex) - self.assertCreateV3(project_name=uuid.uuid4().hex, - project_domain_name=uuid.uuid4().hex) - self.assertCreateV3(project_name=uuid.uuid4().hex, - project_domain_id=uuid.uuid4().hex) - - def test_create_v2_if_no_domain_params(self): - self.stub_discovery() - self.assertCreateV2() - self.assertCreateV2(project_id=uuid.uuid4().hex) - self.assertCreateV2(project_name=uuid.uuid4().hex) - self.assertCreateV2(tenant_id=uuid.uuid4().hex) - self.assertCreateV2(tenant_name=uuid.uuid4().hex) - - def test_v3_params_v2_url(self): - self.stub_discovery(v3=False) - self.assertDiscoveryFailure(domain_name=uuid.uuid4().hex) - - def test_v2_params_v3_url(self): - self.stub_discovery(v2=False) - self.assertCreateV3() - - def test_no_urls(self): - self.stub_discovery(v2=False, v3=False) - self.assertDiscoveryFailure() - - def test_path_based_url_v2(self): - self.stub_url('GET', ['v2.0'], status_code=403) - self.assertCreateV2(auth_url=self.TEST_URL + 'v2.0') - - def test_path_based_url_v3(self): - self.stub_url('GET', ['v3'], status_code=403) - self.assertCreateV3(auth_url=self.TEST_URL + 'v3') - - def test_disc_error_for_failure(self): - self.stub_url('GET', [], status_code=403) - self.assertDiscoveryFailure() - - def test_v3_plugin_from_failure(self): - url = self.TEST_URL + 'v3' - self.stub_url('GET', [], base_url=url, status_code=403) - self.assertCreateV3(auth_url=url) - - def test_unknown_discovery_version(self): - # make a v4 entry that's mostly the same as a v3 - self.stub_discovery(v2=False, v3_id='v4.0') - self.assertDiscoveryFailure() diff --git a/keystoneclient/tests/unit/client_fixtures.py b/keystoneclient/tests/unit/client_fixtures.py deleted file mode 100644 index 6da259c9..00000000 --- a/keystoneclient/tests/unit/client_fixtures.py +++ /dev/null @@ -1,744 +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. - -import contextlib -import os -import uuid -import warnings - -import fixtures -from keystoneauth1 import fixture -from keystoneauth1 import identity as ksa_identity -from keystoneauth1 import session as ksa_session -from oslo_serialization import jsonutils -from oslo_utils import timeutils -import six -import testresources - -from keystoneclient.auth import identity as ksc_identity -from keystoneclient.common import cms -from keystoneclient import session as ksc_session -from keystoneclient import utils -from keystoneclient.v2_0 import client as v2_client -from keystoneclient.v3 import client as v3_client - - -TEST_ROOT_URL = 'http://127.0.0.1:5000/' - -TESTDIR = os.path.dirname(os.path.abspath(__file__)) -ROOTDIR = os.path.normpath(os.path.join(TESTDIR, '..', '..', '..')) -CERTDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'certs') -CMSDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'cms') -KEYDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'private') - - -class BaseFixture(fixtures.Fixture): - - TEST_ROOT_URL = TEST_ROOT_URL - - def __init__(self, requests, deprecations): - super(BaseFixture, self).__init__() - self.requests = requests - self.deprecations = deprecations - self.user_id = uuid.uuid4().hex - self.client = self.new_client() - - -class BaseV2(BaseFixture): - - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v2.0') - - -class OriginalV2(BaseV2): - - def new_client(self): - # Creating a Client not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - return v2_client.Client(username=uuid.uuid4().hex, - user_id=self.user_id, - token=uuid.uuid4().hex, - tenant_name=uuid.uuid4().hex, - auth_url=self.TEST_URL, - endpoint=self.TEST_URL) - - -class KscSessionV2(BaseV2): - - def new_client(self): - t = fixture.V2Token(user_id=self.user_id) - t.set_scope() - - s = t.add_service('identity') - s.add_endpoint(self.TEST_URL) - - d = fixture.V2Discovery(self.TEST_URL) - - self.requests.register_uri('POST', self.TEST_URL + '/tokens', json=t) - - # NOTE(jamielennox): Because of the versioned URL hack here even though - # the V2 URL will be in the service catalog it will be the root URL - # that will be queried for discovery. - self.requests.register_uri('GET', self.TEST_ROOT_URL, - json={'version': d}) - - with self.deprecations.expect_deprecations_here(): - a = ksc_identity.V2Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - auth_url=self.TEST_URL) - - s = ksc_session.Session(auth=a) - - return v2_client.Client(session=s) - - -class KsaSessionV2(BaseV2): - - def new_client(self): - t = fixture.V2Token(user_id=self.user_id) - t.set_scope() - - s = t.add_service('identity') - s.add_endpoint(self.TEST_URL) - - d = fixture.V2Discovery(self.TEST_URL) - - self.requests.register_uri('POST', self.TEST_URL + '/tokens', json=t) - - # NOTE(jamielennox): Because of the versioned URL hack here even though - # the V2 URL will be in the service catalog it will be the root URL - # that will be queried for discovery. - self.requests.register_uri('GET', self.TEST_ROOT_URL, - json={'version': d}) - - a = ksa_identity.V2Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - auth_url=self.TEST_URL) - s = ksa_session.Session(auth=a) - return v2_client.Client(session=s) - - -class BaseV3(BaseFixture): - - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - - -class OriginalV3(BaseV3): - - def new_client(self): - # Creating a Client not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - return v3_client.Client(username=uuid.uuid4().hex, - user_id=self.user_id, - token=uuid.uuid4().hex, - tenant_name=uuid.uuid4().hex, - auth_url=self.TEST_URL, - endpoint=self.TEST_URL) - - -class KscSessionV3(BaseV3): - - def new_client(self): - t = fixture.V3Token(user_id=self.user_id) - t.set_project_scope() - - s = t.add_service('identity') - s.add_standard_endpoints(public=self.TEST_URL, - admin=self.TEST_URL) - - d = fixture.V3Discovery(self.TEST_URL) - - headers = {'X-Subject-Token': uuid.uuid4().hex} - self.requests.register_uri('POST', - self.TEST_URL + '/auth/tokens', - headers=headers, - json=t) - self.requests.register_uri('GET', self.TEST_URL, json={'version': d}) - - with self.deprecations.expect_deprecations_here(): - a = ksc_identity.V3Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - user_domain_id=uuid.uuid4().hex, - auth_url=self.TEST_URL) - - s = ksc_session.Session(auth=a) - - return v3_client.Client(session=s) - - -class KsaSessionV3(BaseV3): - - def new_client(self): - t = fixture.V3Token(user_id=self.user_id) - t.set_project_scope() - - s = t.add_service('identity') - s.add_standard_endpoints(public=self.TEST_URL, - admin=self.TEST_URL) - - d = fixture.V3Discovery(self.TEST_URL) - - headers = {'X-Subject-Token': uuid.uuid4().hex} - self.requests.register_uri('POST', - self.TEST_URL + '/auth/tokens', - headers=headers, - json=t) - self.requests.register_uri('GET', self.TEST_URL, json={'version': d}) - - a = ksa_identity.V3Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - user_domain_id=uuid.uuid4().hex, - auth_url=self.TEST_URL) - s = ksa_session.Session(auth=a) - return v3_client.Client(session=s) - - -def _hash_signed_token_safe(signed_text, **kwargs): - if isinstance(signed_text, six.text_type): - signed_text = signed_text.encode('utf-8') - return utils.hash_signed_token(signed_text, **kwargs) - - -class Examples(fixtures.Fixture): - """Example tokens and certs loaded from the examples directory. - - To use this class correctly, the module needs to override the test suite - class to use testresources.OptimisingTestSuite (otherwise the files will - be read on every test). This is done by defining a load_tests function - in the module, like this: - - def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) - - (see http://docs.python.org/2/library/unittest.html#load-tests-protocol ) - - """ - - def setUp(self): - super(Examples, self).setUp() - - # The data for several tests are signed using openssl and are stored in - # files in the signing subdirectory. In order to keep the values - # consistent between the tests and the signed documents, we read them - # in for use in the tests. - with open(os.path.join(CMSDIR, 'auth_token_scoped.json')) as f: - self.TOKEN_SCOPED_DATA = cms.cms_to_token(f.read()) - - with open(os.path.join(CMSDIR, 'auth_token_scoped.pem')) as f: - self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read()) - self.SIGNED_TOKEN_SCOPED_HASH = _hash_signed_token_safe( - self.SIGNED_TOKEN_SCOPED) - self.SIGNED_TOKEN_SCOPED_HASH_SHA256 = _hash_signed_token_safe( - self.SIGNED_TOKEN_SCOPED, mode='sha256') - with open(os.path.join(CMSDIR, 'auth_token_unscoped.pem')) as f: - self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_scoped.pem')) as f: - self.SIGNED_v3_TOKEN_SCOPED = cms.cms_to_token(f.read()) - self.SIGNED_v3_TOKEN_SCOPED_HASH = _hash_signed_token_safe( - self.SIGNED_v3_TOKEN_SCOPED) - self.SIGNED_v3_TOKEN_SCOPED_HASH_SHA256 = _hash_signed_token_safe( - self.SIGNED_v3_TOKEN_SCOPED, mode='sha256') - with open(os.path.join(CMSDIR, 'auth_token_revoked.pem')) as f: - self.REVOKED_TOKEN = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_scoped_expired.pem')) as f: - self.SIGNED_TOKEN_SCOPED_EXPIRED = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_revoked.pem')) as f: - self.REVOKED_v3_TOKEN = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_scoped.pkiz')) as f: - self.SIGNED_TOKEN_SCOPED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_unscoped.pkiz')) as f: - self.SIGNED_TOKEN_UNSCOPED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_scoped.pkiz')) as f: - self.SIGNED_v3_TOKEN_SCOPED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_revoked.pkiz')) as f: - self.REVOKED_TOKEN_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, - 'auth_token_scoped_expired.pkiz')) as f: - self.SIGNED_TOKEN_SCOPED_EXPIRED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_revoked.pkiz')) as f: - self.REVOKED_v3_TOKEN_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'revocation_list.json')) as f: - self.REVOCATION_LIST = jsonutils.loads(f.read()) - with open(os.path.join(CMSDIR, 'revocation_list.pem')) as f: - self.SIGNED_REVOCATION_LIST = jsonutils.dumps({'signed': f.read()}) - - self.SIGNING_CERT_FILE = os.path.join(CERTDIR, 'signing_cert.pem') - with open(self.SIGNING_CERT_FILE) as f: - self.SIGNING_CERT = f.read() - - self.KERBEROS_BIND = 'USER@REALM' - - self.SIGNING_KEY_FILE = os.path.join(KEYDIR, 'signing_key.pem') - with open(self.SIGNING_KEY_FILE) as f: - self.SIGNING_KEY = f.read() - - self.SIGNING_CA_FILE = os.path.join(CERTDIR, 'cacert.pem') - with open(self.SIGNING_CA_FILE) as f: - self.SIGNING_CA = f.read() - - self.UUID_TOKEN_DEFAULT = "ec6c0710ec2f471498484c1b53ab4f9d" - self.UUID_TOKEN_NO_SERVICE_CATALOG = '8286720fbe4941e69fa8241723bb02df' - self.UUID_TOKEN_UNSCOPED = '731f903721c14827be7b2dc912af7776' - self.UUID_TOKEN_BIND = '3fc54048ad64405c98225ce0897af7c5' - self.UUID_TOKEN_UNKNOWN_BIND = '8885fdf4d42e4fb9879e6379fa1eaf48' - self.VALID_DIABLO_TOKEN = 'b0cf19b55dbb4f20a6ee18e6c6cf1726' - self.v3_UUID_TOKEN_DEFAULT = '5603457654b346fdbb93437bfe76f2f1' - self.v3_UUID_TOKEN_UNSCOPED = 'd34835fdaec447e695a0a024d84f8d79' - self.v3_UUID_TOKEN_DOMAIN_SCOPED = 'e8a7b63aaa4449f38f0c5c05c3581792' - self.v3_UUID_TOKEN_BIND = '2f61f73e1c854cbb9534c487f9bd63c2' - self.v3_UUID_TOKEN_UNKNOWN_BIND = '7ed9781b62cd4880b8d8c6788ab1d1e2' - - revoked_token = self.REVOKED_TOKEN - if isinstance(revoked_token, six.text_type): - revoked_token = revoked_token.encode('utf-8') - self.REVOKED_TOKEN_HASH = utils.hash_signed_token(revoked_token) - self.REVOKED_TOKEN_HASH_SHA256 = utils.hash_signed_token(revoked_token, - mode='sha256') - self.REVOKED_TOKEN_LIST = ( - {'revoked': [{'id': self.REVOKED_TOKEN_HASH, - 'expires': timeutils.utcnow()}]}) - self.REVOKED_TOKEN_LIST_JSON = jsonutils.dumps(self.REVOKED_TOKEN_LIST) - - revoked_v3_token = self.REVOKED_v3_TOKEN - if isinstance(revoked_v3_token, six.text_type): - revoked_v3_token = revoked_v3_token.encode('utf-8') - self.REVOKED_v3_TOKEN_HASH = utils.hash_signed_token(revoked_v3_token) - hash = utils.hash_signed_token(revoked_v3_token, mode='sha256') - self.REVOKED_v3_TOKEN_HASH_SHA256 = hash - self.REVOKED_v3_TOKEN_LIST = ( - {'revoked': [{'id': self.REVOKED_v3_TOKEN_HASH, - 'expires': timeutils.utcnow()}]}) - self.REVOKED_v3_TOKEN_LIST_JSON = jsonutils.dumps( - self.REVOKED_v3_TOKEN_LIST) - - revoked_token_pkiz = self.REVOKED_TOKEN_PKIZ - if isinstance(revoked_token_pkiz, six.text_type): - revoked_token_pkiz = revoked_token_pkiz.encode('utf-8') - self.REVOKED_TOKEN_PKIZ_HASH = utils.hash_signed_token( - revoked_token_pkiz) - revoked_v3_token_pkiz = self.REVOKED_v3_TOKEN_PKIZ - if isinstance(revoked_v3_token_pkiz, six.text_type): - revoked_v3_token_pkiz = revoked_v3_token_pkiz.encode('utf-8') - self.REVOKED_v3_PKIZ_TOKEN_HASH = utils.hash_signed_token( - revoked_v3_token_pkiz) - - self.REVOKED_TOKEN_PKIZ_LIST = ( - {'revoked': [{'id': self.REVOKED_TOKEN_PKIZ_HASH, - 'expires': timeutils.utcnow()}, - {'id': self.REVOKED_v3_PKIZ_TOKEN_HASH, - 'expires': timeutils.utcnow()}, - ]}) - self.REVOKED_TOKEN_PKIZ_LIST_JSON = jsonutils.dumps( - self.REVOKED_TOKEN_PKIZ_LIST) - - self.SIGNED_TOKEN_SCOPED_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_SCOPED) - self.SIGNED_TOKEN_UNSCOPED_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_UNSCOPED) - self.SIGNED_v3_TOKEN_SCOPED_KEY = cms.cms_hash_token( - self.SIGNED_v3_TOKEN_SCOPED) - - self.SIGNED_TOKEN_SCOPED_PKIZ_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_SCOPED_PKIZ) - self.SIGNED_TOKEN_UNSCOPED_PKIZ_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_UNSCOPED_PKIZ) - self.SIGNED_v3_TOKEN_SCOPED_PKIZ_KEY = cms.cms_hash_token( - self.SIGNED_v3_TOKEN_SCOPED_PKIZ) - - self.INVALID_SIGNED_TOKEN = ( - "MIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" - "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "0000000000000000000000000000000000000000000000000000000000000000" - "1111111111111111111111111111111111111111111111111111111111111111" - "2222222222222222222222222222222222222222222222222222222222222222" - "3333333333333333333333333333333333333333333333333333333333333333" - "4444444444444444444444444444444444444444444444444444444444444444" - "5555555555555555555555555555555555555555555555555555555555555555" - "6666666666666666666666666666666666666666666666666666666666666666" - "7777777777777777777777777777777777777777777777777777777777777777" - "8888888888888888888888888888888888888888888888888888888888888888" - "9999999999999999999999999999999999999999999999999999999999999999" - "0000000000000000000000000000000000000000000000000000000000000000") - - self.INVALID_SIGNED_PKIZ_TOKEN = ( - "PKIZ_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" - "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "0000000000000000000000000000000000000000000000000000000000000000" - "1111111111111111111111111111111111111111111111111111111111111111" - "2222222222222222222222222222222222222222222222222222222222222222" - "3333333333333333333333333333333333333333333333333333333333333333" - "4444444444444444444444444444444444444444444444444444444444444444" - "5555555555555555555555555555555555555555555555555555555555555555" - "6666666666666666666666666666666666666666666666666666666666666666" - "7777777777777777777777777777777777777777777777777777777777777777" - "8888888888888888888888888888888888888888888888888888888888888888" - "9999999999999999999999999999999999999999999999999999999999999999" - "0000000000000000000000000000000000000000000000000000000000000000") - - # JSON responses keyed by token ID - self.TOKEN_RESPONSES = { - self.UUID_TOKEN_DEFAULT: { - 'access': { - 'token': { - 'id': self.UUID_TOKEN_DEFAULT, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - 'serviceCatalog': {} - }, - }, - self.VALID_DIABLO_TOKEN: { - 'access': { - 'token': { - 'id': self.VALID_DIABLO_TOKEN, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenantId': 'tenant_id1', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.UUID_TOKEN_UNSCOPED: { - 'access': { - 'token': { - 'id': self.UUID_TOKEN_UNSCOPED, - 'expires': '2020-01-01T00:00:10.000123Z', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.UUID_TOKEN_NO_SERVICE_CATALOG: { - 'access': { - 'token': { - 'id': 'valid-token', - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - } - }, - }, - self.UUID_TOKEN_BIND: { - 'access': { - 'token': { - 'bind': {'kerberos': self.KERBEROS_BIND}, - 'id': self.UUID_TOKEN_BIND, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - 'serviceCatalog': {} - }, - }, - self.UUID_TOKEN_UNKNOWN_BIND: { - 'access': { - 'token': { - 'bind': {'FOO': 'BAR'}, - 'id': self.UUID_TOKEN_UNKNOWN_BIND, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - 'serviceCatalog': {} - }, - }, - self.v3_UUID_TOKEN_DEFAULT: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - self.v3_UUID_TOKEN_UNSCOPED: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - } - } - }, - self.v3_UUID_TOKEN_DOMAIN_SCOPED: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1', - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - self.SIGNED_TOKEN_SCOPED_KEY: { - 'access': { - 'token': { - 'id': self.SIGNED_TOKEN_SCOPED_KEY, - 'expires': '2020-01-01T00:00:10.000123Z', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'tenantId': 'tenant_id1', - 'tenantName': 'tenant_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.SIGNED_TOKEN_UNSCOPED_KEY: { - 'access': { - 'token': { - 'id': self.SIGNED_TOKEN_UNSCOPED_KEY, - 'expires': '2020-01-01T00:00:10.000123Z', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.SIGNED_v3_TOKEN_SCOPED_KEY: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'} - ], - 'catalog': {} - } - }, - self.v3_UUID_TOKEN_BIND: { - 'token': { - 'bind': {'kerberos': self.KERBEROS_BIND}, - 'methods': ['password'], - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - self.v3_UUID_TOKEN_UNKNOWN_BIND: { - 'token': { - 'bind': {'FOO': 'BAR'}, - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - } - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_PKIZ_KEY] = ( - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY]) - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_UNSCOPED_PKIZ_KEY] = ( - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_UNSCOPED_KEY]) - self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_PKIZ_KEY] = ( - self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_KEY]) - - self.JSON_TOKEN_RESPONSES = dict([(k, jsonutils.dumps(v)) for k, v in - self.TOKEN_RESPONSES.items()]) - - -EXAMPLES_RESOURCE = testresources.FixtureResource(Examples()) - - -class Deprecations(fixtures.Fixture): - def setUp(self): - super(Deprecations, self).setUp() - - # If keystoneclient calls any deprecated function this will raise an - # exception. - warnings.filterwarnings('error', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') - self.addCleanup(warnings.resetwarnings) - - def expect_deprecations(self): - """Call this if the test expects to call deprecated function.""" - warnings.resetwarnings() - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') - - @contextlib.contextmanager - def expect_deprecations_here(self): - warnings.resetwarnings() - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') - yield - warnings.resetwarnings() - warnings.filterwarnings('error', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') diff --git a/keystoneclient/tests/unit/generic/__init__.py b/keystoneclient/tests/unit/generic/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/generic/test_client.py b/keystoneclient/tests/unit/generic/test_client.py deleted file mode 100644 index 5c27b6eb..00000000 --- a/keystoneclient/tests/unit/generic/test_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# 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 oslo_serialization import jsonutils - -from keystoneclient.generic import client -from keystoneclient.tests.unit import utils - -BASE_HOST = 'http://keystone.example.com' -BASE_URL = "%s:5000/" % BASE_HOST -V2_URL = "%sv2.0" % BASE_URL - -EXTENSION_NAMESPACE = ("https://docs.openstack.org/identity/api/ext/OS-FAKE/" - "v1.0") -EXTENSION_DESCRIBED = {"href": "https://github.com/openstack/identity-api", - "rel": "describedby", - "type": "text/html"} - -EXTENSION_ALIAS_FOO = "OS-FAKE-FOO" -EXTENSION_NAME_FOO = "OpenStack Keystone Fake Extension Foo" -EXTENSION_FOO = {"alias": EXTENSION_ALIAS_FOO, - "description": "Fake Foo extension to V2.0 API.", - "links": [EXTENSION_DESCRIBED], - "name": EXTENSION_NAME_FOO, - "namespace": EXTENSION_NAMESPACE, - "updated": '2014-01-08T00:00:00Z'} - -EXTENSION_ALIAS_BAR = "OS-FAKE-BAR" -EXTENSION_NAME_BAR = "OpenStack Keystone Fake Extension Bar" -EXTENSION_BAR = {"alias": EXTENSION_ALIAS_BAR, - "description": "Fake Bar extension to V2.0 API.", - "links": [EXTENSION_DESCRIBED], - "name": EXTENSION_NAME_BAR, - "namespace": EXTENSION_NAMESPACE, - "updated": '2014-01-08T00:00:00Z'} - - -def _create_extension_list(extensions): - return jsonutils.dumps({'extensions': {'values': extensions}}) - - -EXTENSION_LIST = _create_extension_list([EXTENSION_FOO, EXTENSION_BAR]) - - -class ClientDiscoveryTests(utils.TestCase): - - def test_discover_extensions_v2(self): - self.requests_mock.get("%s/extensions" % V2_URL, text=EXTENSION_LIST) - # Creating a HTTPClient not using session is deprecated. - # creating a generic client at all is deprecated. - with self.deprecations.expect_deprecations_here(): - extensions = client.Client().discover_extensions(url=V2_URL) - self.assertIn(EXTENSION_ALIAS_FOO, extensions) - self.assertEqual(extensions[EXTENSION_ALIAS_FOO], EXTENSION_NAME_FOO) - self.assertIn(EXTENSION_ALIAS_BAR, extensions) - self.assertEqual(extensions[EXTENSION_ALIAS_BAR], EXTENSION_NAME_BAR) diff --git a/keystoneclient/tests/unit/test_base.py b/keystoneclient/tests/unit/test_base.py deleted file mode 100644 index 0a0fde1c..00000000 --- a/keystoneclient/tests/unit/test_base.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from keystoneauth1.identity import v2 -from keystoneauth1 import session - -from keystoneclient import base -from keystoneclient.tests.unit import utils -from keystoneclient.v2_0 import client -from keystoneclient.v2_0 import roles - - -class HumanReadable(base.Resource): - HUMAN_ID = True - - -class BaseTest(utils.TestCase): - - def test_resource_repr(self): - r = base.Resource(None, dict(foo="bar", baz="spam")) - self.assertEqual(repr(r), "") - - def test_getid(self): - self.assertEqual(base.getid(4), 4) - - class TmpObject(object): - id = 4 - self.assertEqual(base.getid(TmpObject), 4) - - def test_resource_lazy_getattr(self): - auth = v2.Token(token=self.TEST_TOKEN, - auth_url='http://127.0.0.1:5000') - session_ = session.Session(auth=auth) - self.client = client.Client(session=session_) - - self.useFixture(fixtures.MockPatchObject( - self.client._adapter, 'get', side_effect=AttributeError, - autospec=True)) - - f = roles.Role(self.client.roles, {'id': 1, 'name': 'Member'}) - self.assertEqual(f.name, 'Member') - - # Missing stuff still fails after a second get - self.assertRaises(AttributeError, getattr, f, 'blahblah') - - def test_eq(self): - # Two resources with same ID: never equal if their info is not equal - r1 = base.Resource(None, {'id': 1, 'name': 'hi'}) - r2 = base.Resource(None, {'id': 1, 'name': 'hello'}) - self.assertNotEqual(r1, r2) - self.assertTrue(r1 != r2) - - # Two resources with same ID: equal if their info is equal - # The truth of r1==r2 does not imply that r1!=r2 is false in PY2. - # Test that inequality operator is defined and that comparing equal - # items returns False - r1 = base.Resource(None, {'id': 1, 'name': 'hello'}) - r2 = base.Resource(None, {'id': 1, 'name': 'hello'}) - self.assertTrue(r1 == r2) - self.assertFalse(r1 != r2) - - # Two resources of different types: never equal - r1 = base.Resource(None, {'id': 1}) - r2 = roles.Role(None, {'id': 1}) - self.assertNotEqual(r1, r2) - self.assertTrue(r1 != r2) - - # Two resources with no ID: equal if their info is equal - # The truth of r1==r2 does not imply that r1!=r2 is false in PY2. - # Test that inequality operator is defined and that comparing equal - # items returns False. - r1 = base.Resource(None, {'name': 'joe', 'age': 12}) - r2 = base.Resource(None, {'name': 'joe', 'age': 12}) - self.assertTrue(r1 == r2) - self.assertFalse(r1 != r2) - - r1 = base.Resource(None, {'id': 1}) - self.assertNotEqual(r1, object()) - self.assertTrue(r1 != object()) - self.assertNotEqual(r1, {'id': 1}) - self.assertTrue(r1 != {'id': 1}) - - def test_human_id(self): - r = base.Resource(None, {"name": "1 of !"}) - self.assertIsNone(r.human_id) - r = HumanReadable(None, {"name": "1 of !"}) - self.assertEqual(r.human_id, "1-of") - - def test_non_ascii_attr(self): - r_dict = {"name": "foobar", - u"тест": "1234", - u"тест2": u"привет мир"} - - r = base.Resource(None, r_dict) - self.assertEqual(r.name, "foobar") - self.assertEqual(r.to_dict(), r_dict) - - -class ManagerTest(utils.TestCase): - body = {"hello": {"hi": 1}} - url = "/test-url" - - def setUp(self): - super(ManagerTest, self).setUp() - - auth = v2.Token(auth_url='http://127.0.0.1:5000', - token=self.TEST_TOKEN) - session_ = session.Session(auth=auth) - self.client = client.Client(session=session_)._adapter - - self.mgr = base.Manager(self.client) - self.mgr.resource_class = base.Resource - - def test_api(self): - with self.deprecations.expect_deprecations_here(): - self.assertEqual(self.mgr.api, self.client) - - def test_get(self): - get_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'get', autospec=True, return_value=(None, self.body)) - ).mock - rsrc = self.mgr._get(self.url, "hello") - get_mock.assert_called_once_with(self.url) - self.assertEqual(rsrc.hi, 1) - - def test_post(self): - post_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'post', autospec=True, return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._post(self.url, self.body, "hello") - post_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hi, 1) - - post_mock.reset_mock() - - rsrc = self.mgr._post(self.url, self.body, "hello", return_raw=True) - post_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc["hi"], 1) - - def test_put(self): - put_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'put', autospec=True, return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._put(self.url, self.body, "hello") - put_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hi, 1) - - put_mock.reset_mock() - - rsrc = self.mgr._put(self.url, self.body) - put_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hello["hi"], 1) - - def test_patch(self): - patch_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'patch', autospec=True, - return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._patch(self.url, self.body, "hello") - patch_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hi, 1) - - patch_mock.reset_mock() - - rsrc = self.mgr._patch(self.url, self.body) - patch_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hello["hi"], 1) - - def test_update(self): - patch_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'patch', autospec=True, - return_value=(None, self.body)) - ).mock - - put_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'put', autospec=True, return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._update( - self.url, body=self.body, response_key="hello", method="PATCH", - management=False) - patch_mock.assert_called_once_with( - self.url, management=False, body=self.body) - self.assertEqual(rsrc.hi, 1) - - rsrc = self.mgr._update( - self.url, body=None, response_key="hello", method="PUT", - management=True) - put_mock.assert_called_once_with(self.url, management=True, body=None) - self.assertEqual(rsrc.hi, 1) diff --git a/keystoneclient/tests/unit/test_cms.py b/keystoneclient/tests/unit/test_cms.py deleted file mode 100644 index 11078aee..00000000 --- a/keystoneclient/tests/unit/test_cms.py +++ /dev/null @@ -1,201 +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. - -import errno -import os -import subprocess - -import mock -import testresources -from testtools import matchers - -from keystoneclient.common import cms -from keystoneclient import exceptions -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils - - -class CMSTest(utils.TestCase, testresources.ResourcedTestCase): - """Unit tests for the keystoneclient.common.cms module.""" - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def __init__(self, *args, **kwargs): - super(CMSTest, self).__init__(*args, **kwargs) - process = subprocess.Popen(['openssl', 'version'], - stdout=subprocess.PIPE) - out, err = process.communicate() - # Example output: 'OpenSSL 0.9.8za 5 Jun 2014' - openssl_version = out.split()[1] - - if err or openssl_version.startswith(b'0'): - raise Exception('Your version of OpenSSL is not supported. ' - 'You will need to update it to 1.0 or later.') - - def _raise_OSError(*args): - e = OSError() - e.errno = errno.EPIPE - raise e - - def test_cms_verify(self): - self.assertRaises(exceptions.CertificateConfigError, - cms.cms_verify, - 'data', - 'no_exist_cert_file', - 'no_exist_ca_file') - - def test_token_tocms_to_token(self): - with open(os.path.join(client_fixtures.CMSDIR, - 'auth_token_scoped.pem')) as f: - AUTH_TOKEN_SCOPED_CMS = f.read() - - self.assertEqual(cms.token_to_cms(self.examples.SIGNED_TOKEN_SCOPED), - AUTH_TOKEN_SCOPED_CMS) - - tok = cms.cms_to_token(cms.token_to_cms( - self.examples.SIGNED_TOKEN_SCOPED)) - self.assertEqual(tok, self.examples.SIGNED_TOKEN_SCOPED) - - def test_asn1_token(self): - self.assertTrue(cms.is_asn1_token(self.examples.SIGNED_TOKEN_SCOPED)) - self.assertFalse(cms.is_asn1_token('FOOBAR')) - - def test_cms_sign_token_no_files(self): - self.assertRaises(subprocess.CalledProcessError, - cms.cms_sign_token, - self.examples.TOKEN_SCOPED_DATA, - '/no/such/file', '/no/such/key') - - def test_cms_sign_token_no_files_pkiz(self): - self.assertRaises(subprocess.CalledProcessError, - cms.pkiz_sign, - self.examples.TOKEN_SCOPED_DATA, - '/no/such/file', '/no/such/key') - - def test_cms_sign_token_success(self): - self.assertTrue( - cms.pkiz_sign(self.examples.TOKEN_SCOPED_DATA, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_KEY_FILE)) - - def test_cms_verify_token_no_files(self): - self.assertRaises(exceptions.CertificateConfigError, - cms.cms_verify, - self.examples.SIGNED_TOKEN_SCOPED, - '/no/such/file', '/no/such/key') - - def test_cms_verify_token_no_oserror(self): - with mock.patch('subprocess.Popen.communicate', - new=self._raise_OSError): - try: - cms.cms_verify("x", '/no/such/file', '/no/such/key') - except exceptions.CertificateConfigError as e: - self.assertIn('/no/such/file', e.output) - self.assertIn('Hit OSError ', e.output) - else: - self.fail('Expected exceptions.CertificateConfigError') - - def test_cms_verify_token_scoped(self): - cms_content = cms.token_to_cms(self.examples.SIGNED_TOKEN_SCOPED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_verify_token_scoped_expired(self): - cms_content = cms.token_to_cms( - self.examples.SIGNED_TOKEN_SCOPED_EXPIRED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_verify_token_unscoped(self): - cms_content = cms.token_to_cms(self.examples.SIGNED_TOKEN_UNSCOPED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_verify_token_v3_scoped(self): - cms_content = cms.token_to_cms(self.examples.SIGNED_v3_TOKEN_SCOPED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_hash_token_no_token_id(self): - token_id = None - self.assertThat(cms.cms_hash_token(token_id), matchers.Is(None)) - - def test_cms_hash_token_not_pki(self): - """If the token_id is not a PKI token then it returns the token_id.""" - token = 'something' - self.assertFalse(cms.is_asn1_token(token)) - self.assertThat(cms.cms_hash_token(token), matchers.Is(token)) - - def test_cms_hash_token_default_md5(self): - """The default hash method is md5.""" - token = self.examples.SIGNED_TOKEN_SCOPED - token_id_default = cms.cms_hash_token(token) - token_id_md5 = cms.cms_hash_token(token, mode='md5') - self.assertThat(token_id_default, matchers.Equals(token_id_md5)) - # md5 hash is 32 chars. - self.assertThat(token_id_default, matchers.HasLength(32)) - - def test_cms_hash_token_sha256(self): - """Can also hash with sha256.""" - token = self.examples.SIGNED_TOKEN_SCOPED - token_id = cms.cms_hash_token(token, mode='sha256') - # sha256 hash is 64 chars. - self.assertThat(token_id, matchers.HasLength(64)) - - @mock.patch('keystoneclient.common.cms._check_files_accessible') - def test_process_communicate_handle_oserror_epipe(self, files_acc_mock): - process_mock = mock.Mock() - process_mock.communicate = self._raise_OSError - process_mock.stderr = mock.Mock() - process_mock.stderr.read = mock.Mock(return_value='proc stderr') - files_acc_mock.return_value = 1, ('file_path', 'fileerror') - output, err, retcode = cms._process_communicate_handle_oserror( - process_mock, '', []) - - self.assertEqual((output, retcode), ('', 1)) - self.assertIn('file_path', err) - self.assertIn('fileerror', err) - self.assertIn('proc stderr', err) - - @mock.patch('keystoneclient.common.cms._check_files_accessible') - def test_process_communicate_handle_oserror_epipe_files_ok( - self, files_acc_mock): - process_mock = mock.Mock() - process_mock.communicate = self._raise_OSError - process_mock.stderr = mock.Mock() - process_mock.stderr.read = mock.Mock(return_value='proc stderr') - files_acc_mock.return_value = -1, None - output, err, retcode = cms._process_communicate_handle_oserror( - process_mock, '', []) - - self.assertEqual((output, retcode), ('', -1)) - self.assertIn('proc stderr', err) - - def test_process_communicate_handle_oserror_no_exception(self): - process_mock = mock.Mock() - process_mock.communicate.return_value = 'out', 'err' - process_mock.poll.return_value = 0 - - output, err, retcode = cms._process_communicate_handle_oserror( - process_mock, '', []) - - self.assertEqual(output, 'out') - self.assertEqual(err, 'err') - self.assertEqual(retcode, 0) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/test_discovery.py b/keystoneclient/tests/unit/test_discovery.py deleted file mode 100644 index f9d5dbfa..00000000 --- a/keystoneclient/tests/unit/test_discovery.py +++ /dev/null @@ -1,838 +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. - -import re -import uuid - -from keystoneauth1 import fixture -from oslo_serialization import jsonutils -import six -from testtools import matchers - -from keystoneclient import _discover -from keystoneclient.auth import token_endpoint -from keystoneclient import client -from keystoneclient import discover -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils -from keystoneclient.v2_0 import client as v2_client -from keystoneclient.v3 import client as v3_client - - -BASE_HOST = 'http://keystone.example.com' -BASE_URL = "%s:5000/" % BASE_HOST -UPDATED = '2013-03-06T00:00:00Z' - -TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "adminURL": "%s:8774/v1.0" % BASE_HOST, - "region": "RegionOne", - "internalURL": "%s://127.0.0.1:8774/v1.0" % BASE_HOST, - "publicURL": "%s:8774/v1.0/" % BASE_HOST - }], - "type": "nova_compat", - "name": "nova_compat" -}, { - "endpoints": [{ - "adminURL": "http://nova/novapi/admin", - "region": "RegionOne", - "internalURL": "http://nova/novapi/internal", - "publicURL": "http://nova/novapi/public" - }], - "type": "compute", - "name": "nova" -}, { - "endpoints": [{ - "adminURL": "http://glance/glanceapi/admin", - "region": "RegionOne", - "internalURL": "http://glance/glanceapi/internal", - "publicURL": "http://glance/glanceapi/public" - }], - "type": "image", - "name": "glance" -}, { - "endpoints": [{ - "adminURL": "%s:35357/v2.0" % BASE_HOST, - "region": "RegionOne", - "internalURL": "%s:5000/v2.0" % BASE_HOST, - "publicURL": "%s:5000/v2.0" % BASE_HOST - }], - "type": "identity", - "name": "keystone" -}, { - "endpoints": [{ - "adminURL": "http://swift/swiftapi/admin", - "region": "RegionOne", - "internalURL": "http://swift/swiftapi/internal", - "publicURL": "http://swift/swiftapi/public" - }], - "type": "object-store", - "name": "swift" -}] - -V2_URL = "%sv2.0" % BASE_URL -V2_VERSION = fixture.V2Discovery(V2_URL) -V2_VERSION.updated_str = UPDATED - -V2_AUTH_RESPONSE = jsonutils.dumps({ - "access": { - "token": { - "expires": "2020-01-01T00:00:10.000123Z", - "id": 'fakeToken', - "tenant": { - "id": '1' - }, - }, - "user": { - "id": 'test' - }, - "serviceCatalog": TEST_SERVICE_CATALOG, - }, -}) - -V3_URL = "%sv3" % BASE_URL -V3_VERSION = fixture.V3Discovery(V3_URL) -V3_MEDIA_TYPES = V3_VERSION.media_types -V3_VERSION.updated_str = UPDATED - -V3_TOKEN = six.u('3e2813b7ba0b4006840c3825860b86ed'), -V3_AUTH_RESPONSE = jsonutils.dumps({ - "token": { - "methods": [ - "token", - "password" - ], - - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": '1', - "name": 'test-domain' - }, - "id": '1', - "name": 'test-project' - }, - "user": { - "domain": { - "id": '1', - "name": 'test-domain' - }, - "id": '1', - "name": 'test-user' - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - }, -}) - -CINDER_EXAMPLES = { - "versions": [ - { - "status": "CURRENT", - "updated": "2012-01-04T11:33:21Z", - "id": "v1.0", - "links": [ - { - "href": "%sv1/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "CURRENT", - "updated": "2012-11-21T11:33:21Z", - "id": "v2.0", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - } - ] -} - -GLANCE_EXAMPLES = { - "versions": [ - { - "status": "CURRENT", - "id": "v2.2", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "SUPPORTED", - "id": "v2.1", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "SUPPORTED", - "id": "v2.0", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "CURRENT", - "id": "v1.1", - "links": [ - { - "href": "%sv1/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "SUPPORTED", - "id": "v1.0", - "links": [ - { - "href": "%sv1/" % BASE_URL, - "rel": "self" - } - ] - } - ] -} - - -def _create_version_list(versions): - return jsonutils.dumps({'versions': {'values': versions}}) - - -def _create_single_version(version): - return jsonutils.dumps({'version': version}) - - -V3_VERSION_LIST = _create_version_list([V3_VERSION, V2_VERSION]) -V2_VERSION_LIST = _create_version_list([V2_VERSION]) - -V3_VERSION_ENTRY = _create_single_version(V3_VERSION) -V2_VERSION_ENTRY = _create_single_version(V2_VERSION) - - -class AvailableVersionsTests(utils.TestCase): - - def setUp(self): - super(AvailableVersionsTests, self).setUp() - self.deprecations.expect_deprecations() - - def test_available_versions_basics(self): - examples = {'keystone': V3_VERSION_LIST, - 'cinder': jsonutils.dumps(CINDER_EXAMPLES), - 'glance': jsonutils.dumps(GLANCE_EXAMPLES)} - - for path, text in examples.items(): - url = "%s%s" % (BASE_URL, path) - - self.requests_mock.get(url, status_code=300, text=text) - versions = discover.available_versions(url) - - for v in versions: - for n in ('id', 'status', 'links'): - msg = '%s missing from %s version data' % (n, path) - self.assertThat(v, matchers.Annotate(msg, - matchers.Contains(n))) - - def test_available_versions_individual(self): - self.requests_mock.get(V3_URL, status_code=200, text=V3_VERSION_ENTRY) - - versions = discover.available_versions(V3_URL) - - for v in versions: - self.assertEqual(v['id'], 'v3.0') - self.assertEqual(v['status'], 'stable') - self.assertIn('media-types', v) - self.assertIn('links', v) - - def test_available_keystone_data(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - versions = discover.available_versions(BASE_URL) - self.assertEqual(2, len(versions)) - - for v in versions: - self.assertIn(v['id'], ('v2.0', 'v3.0')) - self.assertEqual(v['updated'], UPDATED) - self.assertEqual(v['status'], 'stable') - - if v['id'] == 'v3.0': - self.assertEqual(v['media-types'], V3_MEDIA_TYPES) - - def test_available_cinder_data(self): - text = jsonutils.dumps(CINDER_EXAMPLES) - self.requests_mock.get(BASE_URL, status_code=300, text=text) - - versions = discover.available_versions(BASE_URL) - self.assertEqual(2, len(versions)) - - for v in versions: - self.assertEqual(v['status'], 'CURRENT') - if v['id'] == 'v1.0': - self.assertEqual(v['updated'], '2012-01-04T11:33:21Z') - elif v['id'] == 'v2.0': - self.assertEqual(v['updated'], '2012-11-21T11:33:21Z') - else: - self.fail("Invalid version found") - - def test_available_glance_data(self): - text = jsonutils.dumps(GLANCE_EXAMPLES) - self.requests_mock.get(BASE_URL, status_code=200, text=text) - - versions = discover.available_versions(BASE_URL) - self.assertEqual(5, len(versions)) - - for v in versions: - if v['id'] in ('v2.2', 'v1.1'): - self.assertEqual(v['status'], 'CURRENT') - elif v['id'] in ('v2.1', 'v2.0', 'v1.0'): - self.assertEqual(v['status'], 'SUPPORTED') - else: - self.fail("Invalid version found") - - -class ClientDiscoveryTests(utils.TestCase): - - def setUp(self): - super(ClientDiscoveryTests, self).setUp() - self.deprecations.expect_deprecations() - - def assertCreatesV3(self, **kwargs): - self.requests_mock.post('%s/auth/tokens' % V3_URL, - text=V3_AUTH_RESPONSE, - headers={'X-Subject-Token': V3_TOKEN}) - - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - keystone = client.Client(**kwargs) - self.assertIsInstance(keystone, v3_client.Client) - return keystone - - def assertCreatesV2(self, **kwargs): - self.requests_mock.post("%s/tokens" % V2_URL, text=V2_AUTH_RESPONSE) - - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - keystone = client.Client(**kwargs) - self.assertIsInstance(keystone, v2_client.Client) - return keystone - - def assertVersionNotAvailable(self, **kwargs): - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - - self.assertRaises(exceptions.VersionNotAvailable, - client.Client, **kwargs) - - def assertDiscoveryFailure(self, **kwargs): - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - - self.assertRaises(exceptions.DiscoveryFailure, - client.Client, **kwargs) - - def test_discover_v3(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.assertCreatesV3(auth_url=BASE_URL) - - def test_discover_v2(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V2_VERSION_LIST) - self.requests_mock.post("%s/tokens" % V2_URL, text=V2_AUTH_RESPONSE) - - self.assertCreatesV2(auth_url=BASE_URL) - - def test_discover_endpoint_v2(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V2_VERSION_LIST) - self.assertCreatesV2(endpoint=BASE_URL, token='fake-token') - - def test_discover_endpoint_v3(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - self.assertCreatesV3(endpoint=BASE_URL, token='fake-token') - - def test_discover_invalid_major_version(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.assertVersionNotAvailable(auth_url=BASE_URL, version=5) - - def test_discover_200_response_fails(self): - self.requests_mock.get(BASE_URL, text='ok') - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_discover_minor_greater_than_available_fails(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.assertVersionNotAvailable(endpoint=BASE_URL, version=3.4) - - def test_discover_individual_version_v2(self): - self.requests_mock.get(V2_URL, text=V2_VERSION_ENTRY) - - self.assertCreatesV2(auth_url=V2_URL) - - def test_discover_individual_version_v3(self): - self.requests_mock.get(V3_URL, text=V3_VERSION_ENTRY) - - self.assertCreatesV3(auth_url=V3_URL) - - def test_discover_individual_endpoint_v2(self): - self.requests_mock.get(V2_URL, text=V2_VERSION_ENTRY) - self.assertCreatesV2(endpoint=V2_URL, token='fake-token') - - def test_discover_individual_endpoint_v3(self): - self.requests_mock.get(V3_URL, text=V3_VERSION_ENTRY) - self.assertCreatesV3(endpoint=V3_URL, token='fake-token') - - def test_discover_fail_to_create_bad_individual_version(self): - self.requests_mock.get(V2_URL, text=V2_VERSION_ENTRY) - self.requests_mock.get(V3_URL, text=V3_VERSION_ENTRY) - - self.assertVersionNotAvailable(auth_url=V2_URL, version=3) - self.assertVersionNotAvailable(auth_url=V3_URL, version=2) - - def test_discover_unstable_versions(self): - version_list = fixture.DiscoveryList(BASE_URL, v3_status='beta') - self.requests_mock.get(BASE_URL, status_code=300, json=version_list) - - self.assertCreatesV2(auth_url=BASE_URL) - self.assertVersionNotAvailable(auth_url=BASE_URL, version=3) - self.assertCreatesV3(auth_url=BASE_URL, unstable=True) - - def test_discover_forwards_original_ip(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - ip = '192.168.1.1' - self.assertCreatesV3(auth_url=BASE_URL, original_ip=ip) - - self.assertThat(self.requests_mock.last_request.headers['forwarded'], - matchers.Contains(ip)) - - def test_discover_bad_args(self): - self.assertRaises(exceptions.DiscoveryFailure, - client.Client) - - def test_discover_bad_response(self): - self.requests_mock.get(BASE_URL, status_code=300, json={'FOO': 'BAR'}) - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_discovery_ignore_invalid(self): - resp = [{'id': 'v3.0', - 'links': [1, 2, 3, 4], # invalid links - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED}] - self.requests_mock.get(BASE_URL, status_code=300, - text=_create_version_list(resp)) - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_ignore_entry_without_links(self): - v3 = V3_VERSION.copy() - v3['links'] = [] - self.requests_mock.get(BASE_URL, status_code=300, - text=_create_version_list([v3, V2_VERSION])) - self.assertCreatesV2(auth_url=BASE_URL) - - def test_ignore_entry_without_status(self): - v3 = V3_VERSION.copy() - del v3['status'] - self.requests_mock.get(BASE_URL, status_code=300, - text=_create_version_list([v3, V2_VERSION])) - self.assertCreatesV2(auth_url=BASE_URL) - - def test_greater_version_than_required(self): - versions = fixture.DiscoveryList(BASE_URL, v3_id='v3.6') - self.requests_mock.get(BASE_URL, json=versions) - self.assertCreatesV3(auth_url=BASE_URL, version=(3, 4)) - - def test_lesser_version_than_required(self): - versions = fixture.DiscoveryList(BASE_URL, v3_id='v3.4') - self.requests_mock.get(BASE_URL, json=versions) - self.assertVersionNotAvailable(auth_url=BASE_URL, version=(3, 6)) - - def test_bad_response(self): - self.requests_mock.get(BASE_URL, status_code=300, text="Ugly Duckling") - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_pass_client_arguments(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V2_VERSION_LIST) - kwargs = {'original_ip': '100', 'use_keyring': False, - 'stale_duration': 15} - - cl = self.assertCreatesV2(auth_url=BASE_URL, **kwargs) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(cl.original_ip, '100') - self.assertEqual(cl.stale_duration, 15) - self.assertFalse(cl.use_keyring) - - def test_overriding_stored_kwargs(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.requests_mock.post("%s/auth/tokens" % V3_URL, - text=V3_AUTH_RESPONSE, - headers={'X-Subject-Token': V3_TOKEN}) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL, debug=False, - username='foo') - client = disc.create_client(debug=True, password='bar') - - self.assertIsInstance(client, v3_client.Client) - self.assertFalse(disc._client_kwargs['debug']) - self.assertEqual(client.username, 'foo') - self.assertEqual(client.password, 'bar') - - def test_available_versions(self): - self.requests_mock.get(BASE_URL, - status_code=300, - text=V3_VERSION_ENTRY) - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - with self.deprecations.expect_deprecations_here(): - versions = disc.available_versions() - self.assertEqual(1, len(versions)) - self.assertEqual(V3_VERSION, versions[0]) - - def test_unknown_client_version(self): - V4_VERSION = {'id': 'v4.0', - 'links': [{'href': 'http://url', 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED} - versions = fixture.DiscoveryList() - versions.add_version(V4_VERSION) - self.requests_mock.get(BASE_URL, status_code=300, json=versions) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - self.assertRaises(exceptions.DiscoveryFailure, - disc.create_client, version=4) - - def test_discovery_fail_for_missing_v3(self): - versions = fixture.DiscoveryList(v2=True, v3=False) - self.requests_mock.get(BASE_URL, status_code=300, json=versions) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - self.assertRaises(exceptions.DiscoveryFailure, - disc.create_client, version=(3, 0)) - - def _do_discovery_call(self, token=None, **kwargs): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - if not token: - token = uuid.uuid4().hex - - url = 'http://testurl' - - with self.deprecations.expect_deprecations_here(): - a = token_endpoint.Token(url, token) - s = session.Session(auth=a) - - # will default to true as there is a plugin on the session - discover.Discover(s, auth_url=BASE_URL, **kwargs) - - self.assertEqual(BASE_URL, self.requests_mock.last_request.url) - - def test_setting_authenticated_true(self): - token = uuid.uuid4().hex - self._do_discovery_call(token) - self.assertRequestHeaderEqual('X-Auth-Token', token) - - def test_setting_authenticated_false(self): - self._do_discovery_call(authenticated=False) - self.assertNotIn('X-Auth-Token', - self.requests_mock.last_request.headers) - - -class DiscoverQueryTests(utils.TestCase): - - def test_available_keystone_data(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - versions = disc.version_data() - - self.assertEqual((2, 0), versions[0]['version']) - self.assertEqual('stable', versions[0]['raw_status']) - self.assertEqual(V2_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[1]['version']) - self.assertEqual('stable', versions[1]['raw_status']) - self.assertEqual(V3_URL, versions[1]['url']) - - version = disc.data_for('v3.0') - self.assertEqual((3, 0), version['version']) - self.assertEqual('stable', version['raw_status']) - self.assertEqual(V3_URL, version['url']) - - version = disc.data_for(2) - self.assertEqual((2, 0), version['version']) - self.assertEqual('stable', version['raw_status']) - self.assertEqual(V2_URL, version['url']) - - self.assertIsNone(disc.url_for('v4')) - self.assertEqual(V3_URL, disc.url_for('v3')) - self.assertEqual(V2_URL, disc.url_for('v2')) - - def test_available_cinder_data(self): - text = jsonutils.dumps(CINDER_EXAMPLES) - self.requests_mock.get(BASE_URL, status_code=300, text=text) - - v1_url = "%sv1/" % BASE_URL - v2_url = "%sv2/" % BASE_URL - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - versions = disc.version_data() - - self.assertEqual((1, 0), versions[0]['version']) - self.assertEqual('CURRENT', versions[0]['raw_status']) - self.assertEqual(v1_url, versions[0]['url']) - self.assertEqual((2, 0), versions[1]['version']) - self.assertEqual('CURRENT', versions[1]['raw_status']) - self.assertEqual(v2_url, versions[1]['url']) - - version = disc.data_for('v2.0') - self.assertEqual((2, 0), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v2_url, version['url']) - - version = disc.data_for(1) - self.assertEqual((1, 0), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v1_url, version['url']) - - self.assertIsNone(disc.url_for('v3')) - self.assertEqual(v2_url, disc.url_for('v2')) - self.assertEqual(v1_url, disc.url_for('v1')) - - def test_available_glance_data(self): - text = jsonutils.dumps(GLANCE_EXAMPLES) - self.requests_mock.get(BASE_URL, text=text) - - v1_url = "%sv1/" % BASE_URL - v2_url = "%sv2/" % BASE_URL - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - versions = disc.version_data() - - self.assertEqual((1, 0), versions[0]['version']) - self.assertEqual('SUPPORTED', versions[0]['raw_status']) - self.assertEqual(v1_url, versions[0]['url']) - self.assertEqual((1, 1), versions[1]['version']) - self.assertEqual('CURRENT', versions[1]['raw_status']) - self.assertEqual(v1_url, versions[1]['url']) - self.assertEqual((2, 0), versions[2]['version']) - self.assertEqual('SUPPORTED', versions[2]['raw_status']) - self.assertEqual(v2_url, versions[2]['url']) - self.assertEqual((2, 1), versions[3]['version']) - self.assertEqual('SUPPORTED', versions[3]['raw_status']) - self.assertEqual(v2_url, versions[3]['url']) - self.assertEqual((2, 2), versions[4]['version']) - self.assertEqual('CURRENT', versions[4]['raw_status']) - self.assertEqual(v2_url, versions[4]['url']) - - for ver in (2, 2.1, 2.2): - version = disc.data_for(ver) - self.assertEqual((2, 2), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v2_url, version['url']) - self.assertEqual(v2_url, disc.url_for(ver)) - - for ver in (1, 1.1): - version = disc.data_for(ver) - self.assertEqual((1, 1), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v1_url, version['url']) - self.assertEqual(v1_url, disc.url_for(ver)) - - self.assertIsNone(disc.url_for('v3')) - self.assertIsNone(disc.url_for('v2.3')) - - def test_allow_deprecated(self): - status = 'deprecated' - version_list = [{'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': status, - 'updated': UPDATED}] - text = jsonutils.dumps({'versions': version_list}) - self.requests_mock.get(BASE_URL, text=text) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - # deprecated is allowed by default - versions = disc.version_data(allow_deprecated=False) - self.assertEqual(0, len(versions)) - - versions = disc.version_data(allow_deprecated=True) - self.assertEqual(1, len(versions)) - self.assertEqual(status, versions[0]['raw_status']) - self.assertEqual(V3_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[0]['version']) - - def test_allow_experimental(self): - status = 'experimental' - version_list = [{'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': status, - 'updated': UPDATED}] - text = jsonutils.dumps({'versions': version_list}) - self.requests_mock.get(BASE_URL, text=text) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - versions = disc.version_data() - self.assertEqual(0, len(versions)) - - versions = disc.version_data(allow_experimental=True) - self.assertEqual(1, len(versions)) - self.assertEqual(status, versions[0]['raw_status']) - self.assertEqual(V3_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[0]['version']) - - def test_allow_unknown(self): - status = 'abcdef' - version_list = fixture.DiscoveryList(BASE_URL, v2=False, - v3_status=status) - self.requests_mock.get(BASE_URL, json=version_list) - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - versions = disc.version_data() - self.assertEqual(0, len(versions)) - - versions = disc.version_data(allow_unknown=True) - self.assertEqual(1, len(versions)) - self.assertEqual(status, versions[0]['raw_status']) - self.assertEqual(V3_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[0]['version']) - - def test_ignoring_invalid_lnks(self): - version_list = [{'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED}, - {'id': 'v3.1', - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED}, - {'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED, - 'links': [{'href': V3_URL, 'rel': 'self'}], - }] - - text = jsonutils.dumps({'versions': version_list}) - self.requests_mock.get(BASE_URL, text=text) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - # raw_version_data will return all choices, even invalid ones - versions = disc.raw_version_data() - self.assertEqual(3, len(versions)) - - # only the version with both id and links will be actually returned - versions = disc.version_data() - self.assertEqual(1, len(versions)) - - -class CatalogHackTests(utils.TestCase): - - TEST_URL = 'http://keystone.server:5000/v2.0' - OTHER_URL = 'http://other.server:5000/path' - - IDENTITY = 'identity' - - BASE_URL = 'http://keystone.server:5000/' - V2_URL = BASE_URL + 'v2.0' - V3_URL = BASE_URL + 'v3' - - def setUp(self): - super(CatalogHackTests, self).setUp() - self.hacks = _discover._VersionHacks() - self.hacks.add_discover_hack(self.IDENTITY, - re.compile('/v2.0/?$'), - '/') - - def test_version_hacks(self): - self.assertEqual(self.BASE_URL, - self.hacks.get_discover_hack(self.IDENTITY, - self.V2_URL)) - - self.assertEqual(self.BASE_URL, - self.hacks.get_discover_hack(self.IDENTITY, - self.V2_URL + '/')) - - self.assertEqual(self.OTHER_URL, - self.hacks.get_discover_hack(self.IDENTITY, - self.OTHER_URL)) - - def test_ignored_non_service_type(self): - self.assertEqual(self.V2_URL, - self.hacks.get_discover_hack('other', self.V2_URL)) - - -class DiscoverUtils(utils.TestCase): - - def test_version_number(self): - def assertVersion(inp, out): - self.assertEqual(out, _discover.normalize_version_number(inp)) - - def versionRaises(inp): - self.assertRaises(TypeError, - _discover.normalize_version_number, - inp) - - assertVersion('v1.2', (1, 2)) - assertVersion('v11', (11, 0)) - assertVersion('1.2', (1, 2)) - assertVersion('1.5.1', (1, 5, 1)) - assertVersion('1', (1, 0)) - assertVersion(1, (1, 0)) - assertVersion(5.2, (5, 2)) - assertVersion((6, 1), (6, 1)) - assertVersion([1, 4], (1, 4)) - - versionRaises('hello') - versionRaises('1.a') - versionRaises('vacuum') diff --git a/keystoneclient/tests/unit/test_ec2utils.py b/keystoneclient/tests/unit/test_ec2utils.py deleted file mode 100644 index 1d8809b2..00000000 --- a/keystoneclient/tests/unit/test_ec2utils.py +++ /dev/null @@ -1,306 +0,0 @@ -# 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. - -from __future__ import unicode_literals - -import testtools - -from keystoneclient.contrib.ec2 import utils -from keystoneclient.tests.unit import client_fixtures - - -class Ec2SignerTest(testtools.TestCase): - - def setUp(self): - super(Ec2SignerTest, self).setUp() - self.useFixture(client_fixtures.Deprecations()) - self.access = '966afbde20b84200ae4e62e09acf46b2' - self.secret = '89cdf9e94e2643cab35b8b8ac5a51f83' - self.signer = utils.Ec2Signer(self.secret) - - def test_v4_creds_header(self): - auth_str = 'AWS4-HMAC-SHA256 blah' - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {}, - 'headers': {'Authorization': auth_str}} - self.assertTrue(self.signer._v4_creds(credentials)) - - def test_v4_creds_param(self): - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'X-Amz-Algorithm': 'AWS4-HMAC-SHA256'}, - 'headers': {}} - self.assertTrue(self.signer._v4_creds(credentials)) - - def test_v4_creds_false(self): - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '0', - 'AWSAccessKeyId': self.access, - 'Timestamp': '2012-11-27T11:47:02Z', - 'Action': 'Foo'}} - self.assertFalse(self.signer._v4_creds(credentials)) - - def test_generate_0(self): - """Test generate function for v0 signature.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '0', - 'AWSAccessKeyId': self.access, - 'Timestamp': '2012-11-27T11:47:02Z', - 'Action': 'Foo'}} - signature = self.signer.generate(credentials) - expected = 'SmXQEZAUdQw5glv5mX8mmixBtas=' - self.assertEqual(signature, expected) - - def test_generate_1(self): - """Test generate function for v1 signature.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '1', - 'AWSAccessKeyId': self.access}} - signature = self.signer.generate(credentials) - expected = 'VRnoQH/EhVTTLhwRLfuL7jmFW9c=' - self.assertEqual(signature, expected) - - def test_generate_v2_SHA256(self): - """Test generate function for v2 signature, SHA256.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '2', - 'AWSAccessKeyId': self.access}} - signature = self.signer.generate(credentials) - expected = 'odsGmT811GffUO0Eu13Pq+xTzKNIjJ6NhgZU74tYX/w=' - self.assertEqual(signature, expected) - - def test_generate_v2_SHA1(self): - """Test generate function for v2 signature, SHA1.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '2', - 'AWSAccessKeyId': self.access}} - self.signer.hmac_256 = None - signature = self.signer.generate(credentials) - expected = 'ZqCxMI4ZtTXWI175743mJ0hy/Gc=' - self.assertEqual(signature, expected) - - def test_generate_v4(self): - """Test v4 generator with data from AWS docs example. - - see: - http://docs.aws.amazon.com/general/latest/gr/ - sigv4-create-canonical-request.html - and - http://docs.aws.amazon.com/general/latest/gr/ - sigv4-signed-request-examples.html - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'iam.amazonaws.com', - 'Authorization': auth_str} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {'Action': 'CreateUser', - 'UserName': 'NewUser', - 'Version': '2010-05-08', - 'X-Amz-Algorithm': 'AWS4-HMAC-SHA256', - 'X-Amz-Credential': 'AKIAEXAMPLE/20140611/' - 'us-east-1/iam/aws4_request', - 'X-Amz-Date': '20140611T231318Z', - 'X-Amz-Expires': '30', - 'X-Amz-SignedHeaders': 'host', - 'X-Amz-Signature': 'ced6826de92d2bdeed8f846f0bf508e8' - '559e98e4b0199114b84c54174deb456c'} - credentials = {'host': 'iam.amazonaws.com', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - expected = ('ced6826de92d2bdeed8f846f0bf508e8' - '559e98e4b0199114b84c54174deb456c') - self.assertEqual(signature, expected) - - def test_generate_v4_port(self): - """Test v4 generator with host:port format.""" - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('26dd92ea79aaa49f533d13b1055acdc' - 'd7d7321460d64621f96cc79c4f4d4ab2b') - self.assertEqual(signature, expected) - - def test_generate_v4_port_strip(self): - """Test v4 generator with host:port format for old boto version. - - Validate for old (<2.9.3) version of boto, where the port should - be stripped to match boto behavior. - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str, - 'User-Agent': 'Boto/2.9.2 (linux2)'} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('9a4b2276a5039ada3b90f72ea8ec1745' - '14b92b909fb106b22ad910c5d75a54f4') - self.assertEqual(expected, signature) - - def test_generate_v4_port_nostrip(self): - """Test v4 generator with host:port format for new boto version. - - Validate for new (>=2.9.3) version of boto, where the port should - not be stripped. - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str, - 'User-Agent': 'Boto/2.9.3 (linux2)'} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('26dd92ea79aaa49f533d13b1055acdc' - 'd7d7321460d64621f96cc79c4f4d4ab2b') - self.assertEqual(expected, signature) - - def test_generate_v4_port_malformed_version(self): - """Test v4 generator with host:port format for malformed boto version. - - Validate for malformed version of boto, where the port should - not be stripped. - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str, - 'User-Agent': 'Boto/2.922 (linux2)'} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('26dd92ea79aaa49f533d13b1055acdc' - 'd7d7321460d64621f96cc79c4f4d4ab2b') - self.assertEqual(expected, signature) diff --git a/keystoneclient/tests/unit/test_fixtures.py b/keystoneclient/tests/unit/test_fixtures.py deleted file mode 100644 index d7fd26e6..00000000 --- a/keystoneclient/tests/unit/test_fixtures.py +++ /dev/null @@ -1,251 +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. - -import uuid - - -from keystoneclient import fixture -from keystoneclient.tests.unit import utils - - -class V2TokenTests(utils.TestCase): - - def test_unscoped(self): - token_id = uuid.uuid4().hex - user_id = uuid.uuid4().hex - user_name = uuid.uuid4().hex - - token = fixture.V2Token(token_id=token_id, - user_id=user_id, - user_name=user_name) - - self.assertEqual(token_id, token.token_id) - self.assertEqual(token_id, token['access']['token']['id']) - self.assertEqual(user_id, token.user_id) - self.assertEqual(user_id, token['access']['user']['id']) - self.assertEqual(user_name, token.user_name) - self.assertEqual(user_name, token['access']['user']['name']) - self.assertIsNone(token.trust_id) - - def test_tenant_scoped(self): - tenant_id = uuid.uuid4().hex - tenant_name = uuid.uuid4().hex - - token = fixture.V2Token(tenant_id=tenant_id, - tenant_name=tenant_name) - - self.assertEqual(tenant_id, token.tenant_id) - self.assertEqual(tenant_id, token['access']['token']['tenant']['id']) - self.assertEqual(tenant_name, token.tenant_name) - tn = token['access']['token']['tenant']['name'] - self.assertEqual(tenant_name, tn) - self.assertIsNone(token.trust_id) - - def test_trust_scoped(self): - trust_id = uuid.uuid4().hex - trustee_user_id = uuid.uuid4().hex - - token = fixture.V2Token(trust_id=trust_id, - trustee_user_id=trustee_user_id) - trust = token['access']['trust'] - - self.assertEqual(trust_id, token.trust_id) - self.assertEqual(trust_id, trust['id']) - self.assertEqual(trustee_user_id, token.trustee_user_id) - self.assertEqual(trustee_user_id, trust['trustee_user_id']) - - def test_roles(self): - role_id1 = uuid.uuid4().hex - role_name1 = uuid.uuid4().hex - role_id2 = uuid.uuid4().hex - role_name2 = uuid.uuid4().hex - - token = fixture.V2Token() - token.add_role(id=role_id1, name=role_name1) - token.add_role(id=role_id2, name=role_name2) - - role_names = token['access']['user']['roles'] - role_ids = token['access']['metadata']['roles'] - - self.assertEqual(set([role_id1, role_id2]), set(role_ids)) - for r in (role_name1, role_name2): - self.assertIn({'name': r}, role_names) - - def test_services(self): - service_type = uuid.uuid4().hex - service_name = uuid.uuid4().hex - endpoint_id = uuid.uuid4().hex - region = uuid.uuid4().hex - - public = uuid.uuid4().hex - admin = uuid.uuid4().hex - internal = uuid.uuid4().hex - - token = fixture.V2Token() - svc = token.add_service(type=service_type, name=service_name) - - svc.add_endpoint(public=public, - admin=admin, - internal=internal, - region=region, - id=endpoint_id) - - self.assertEqual(1, len(token['access']['serviceCatalog'])) - service = token['access']['serviceCatalog'][0]['endpoints'][0] - - self.assertEqual(public, service['publicURL']) - self.assertEqual(internal, service['internalURL']) - self.assertEqual(admin, service['adminURL']) - self.assertEqual(region, service['region']) - self.assertEqual(endpoint_id, service['id']) - - -class V3TokenTests(utils.TestCase): - - def test_unscoped(self): - user_id = uuid.uuid4().hex - user_name = uuid.uuid4().hex - user_domain_id = uuid.uuid4().hex - user_domain_name = uuid.uuid4().hex - - token = fixture.V3Token(user_id=user_id, - user_name=user_name, - user_domain_id=user_domain_id, - user_domain_name=user_domain_name) - - self.assertEqual(user_id, token.user_id) - self.assertEqual(user_id, token['token']['user']['id']) - self.assertEqual(user_name, token.user_name) - self.assertEqual(user_name, token['token']['user']['name']) - - user_domain = token['token']['user']['domain'] - - self.assertEqual(user_domain_id, token.user_domain_id) - self.assertEqual(user_domain_id, user_domain['id']) - self.assertEqual(user_domain_name, token.user_domain_name) - self.assertEqual(user_domain_name, user_domain['name']) - - def test_project_scoped(self): - project_id = uuid.uuid4().hex - project_name = uuid.uuid4().hex - project_domain_id = uuid.uuid4().hex - project_domain_name = uuid.uuid4().hex - - token = fixture.V3Token(project_id=project_id, - project_name=project_name, - project_domain_id=project_domain_id, - project_domain_name=project_domain_name) - - self.assertEqual(project_id, token.project_id) - self.assertEqual(project_id, token['token']['project']['id']) - self.assertEqual(project_name, token.project_name) - self.assertEqual(project_name, token['token']['project']['name']) - - project_domain = token['token']['project']['domain'] - - self.assertEqual(project_domain_id, token.project_domain_id) - self.assertEqual(project_domain_id, project_domain['id']) - self.assertEqual(project_domain_name, token.project_domain_name) - self.assertEqual(project_domain_name, project_domain['name']) - - def test_domain_scoped(self): - domain_id = uuid.uuid4().hex - domain_name = uuid.uuid4().hex - - token = fixture.V3Token(domain_id=domain_id, - domain_name=domain_name) - - self.assertEqual(domain_id, token.domain_id) - self.assertEqual(domain_id, token['token']['domain']['id']) - self.assertEqual(domain_name, token.domain_name) - self.assertEqual(domain_name, token['token']['domain']['name']) - - def test_roles(self): - role1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} - role2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} - - token = fixture.V3Token() - token.add_role(**role1) - token.add_role(**role2) - - self.assertEqual(2, len(token['token']['roles'])) - - self.assertIn(role1, token['token']['roles']) - self.assertIn(role2, token['token']['roles']) - - def test_trust_scoped(self): - trust_id = uuid.uuid4().hex - trustee_user_id = uuid.uuid4().hex - trustor_user_id = uuid.uuid4().hex - impersonation = True - - token = fixture.V3Token(trust_id=trust_id, - trustee_user_id=trustee_user_id, - trustor_user_id=trustor_user_id, - trust_impersonation=impersonation) - - trust = token['token']['OS-TRUST:trust'] - self.assertEqual(trust_id, token.trust_id) - self.assertEqual(trust_id, trust['id']) - self.assertEqual(trustee_user_id, token.trustee_user_id) - self.assertEqual(trustee_user_id, trust['trustee_user']['id']) - self.assertEqual(trustor_user_id, token.trustor_user_id) - self.assertEqual(trustor_user_id, trust['trustor_user']['id']) - self.assertEqual(impersonation, token.trust_impersonation) - self.assertEqual(impersonation, trust['impersonation']) - - def test_oauth_scoped(self): - access_id = uuid.uuid4().hex - consumer_id = uuid.uuid4().hex - - token = fixture.V3Token(oauth_access_token_id=access_id, - oauth_consumer_id=consumer_id) - - oauth = token['token']['OS-OAUTH1'] - - self.assertEqual(access_id, token.oauth_access_token_id) - self.assertEqual(access_id, oauth['access_token_id']) - self.assertEqual(consumer_id, token.oauth_consumer_id) - self.assertEqual(consumer_id, oauth['consumer_id']) - - def test_catalog(self): - service_type = uuid.uuid4().hex - service_name = uuid.uuid4().hex - service_id = uuid.uuid4().hex - region = uuid.uuid4().hex - endpoints = {'public': uuid.uuid4().hex, - 'internal': uuid.uuid4().hex, - 'admin': uuid.uuid4().hex} - - token = fixture.V3Token() - svc = token.add_service(type=service_type, - name=service_name, - id=service_id) - svc.add_standard_endpoints(region=region, **endpoints) - - self.assertEqual(1, len(token['token']['catalog'])) - service = token['token']['catalog'][0] - self.assertEqual(3, len(service['endpoints'])) - - self.assertEqual(service_name, service['name']) - self.assertEqual(service_type, service['type']) - self.assertEqual(service_id, service['id']) - - for endpoint in service['endpoints']: - # assert an id exists for each endpoint, remove it to make testing - # the endpoint content below easier. - self.assertTrue(endpoint.pop('id')) - - for interface, url in endpoints.items(): - endpoint = {'interface': interface, 'url': url, - 'region': region, 'region_id': region} - self.assertIn(endpoint, service['endpoints']) diff --git a/keystoneclient/tests/unit/test_http.py b/keystoneclient/tests/unit/test_http.py deleted file mode 100644 index af9058f9..00000000 --- a/keystoneclient/tests/unit/test_http.py +++ /dev/null @@ -1,218 +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. - -import logging - -import six -from testtools import matchers - -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -RESPONSE_BODY = '{"hi": "there"}' - - -def get_client(): - cl = httpclient.HTTPClient(username="username", password="password", - project_id="tenant", auth_url="auth_test") - return cl - - -def get_authed_client(): - cl = get_client() - cl.management_url = "http://127.0.0.1:5000" - cl.auth_token = "token" - return cl - - -class ClientTest(utils.TestCase): - - TEST_URL = 'http://127.0.0.1:5000/hi' - - def test_unauthorized_client_requests(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_client() - self.assertRaises(exceptions.AuthorizationFailure, cl.get, '/hi') - self.assertRaises(exceptions.AuthorizationFailure, cl.post, '/hi') - self.assertRaises(exceptions.AuthorizationFailure, cl.put, '/hi') - self.assertRaises(exceptions.AuthorizationFailure, cl.delete, '/hi') - - def test_get(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - self.stub_url('GET', text=RESPONSE_BODY) - - with self.deprecations.expect_deprecations_here(): - resp, body = cl.get("/hi") - self.assertEqual(self.requests_mock.last_request.method, 'GET') - self.assertEqual(self.requests_mock.last_request.url, self.TEST_URL) - - self.assertRequestHeaderEqual('X-Auth-Token', 'token') - self.assertRequestHeaderEqual('User-Agent', httpclient.USER_AGENT) - - # Automatic JSON parsing - self.assertEqual(body, {"hi": "there"}) - - def test_get_error_with_plaintext_resp(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - self.stub_url('GET', status_code=400, - text='Some evil plaintext string') - - self.assertRaises(exceptions.BadRequest, cl.get, '/hi') - - def test_get_error_with_json_resp(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - err_response = { - "error": { - "code": 400, - "title": "Error title", - "message": "Error message string" - } - } - self.stub_url('GET', status_code=400, json=err_response) - exc_raised = False - try: - with self.deprecations.expect_deprecations_here(): - cl.get('/hi') - except exceptions.BadRequest as exc: - exc_raised = True - self.assertEqual(exc.message, "Error message string (HTTP 400)") - self.assertTrue(exc_raised, 'Exception not raised.') - - def test_post(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - self.stub_url('POST') - with self.deprecations.expect_deprecations_here(): - cl.post("/hi", body=[1, 2, 3]) - - self.assertEqual(self.requests_mock.last_request.method, 'POST') - self.assertEqual(self.requests_mock.last_request.body, '[1, 2, 3]') - - self.assertRequestHeaderEqual('X-Auth-Token', 'token') - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('User-Agent', httpclient.USER_AGENT) - - def test_forwarded_for(self): - ORIGINAL_IP = "10.100.100.1" - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username="username", - password="password", - project_id="tenant", - auth_url="auth_test", - original_ip=ORIGINAL_IP) - - self.stub_url('GET') - - with self.deprecations.expect_deprecations_here(): - cl.request(self.TEST_URL, 'GET') - forwarded = "for=%s;by=%s" % (ORIGINAL_IP, httpclient.USER_AGENT) - self.assertRequestHeaderEqual('Forwarded', forwarded) - - def test_client_deprecated(self): - # Can resolve symbols from the keystoneclient.client module. - # keystoneclient.client was deprecated and renamed to - # keystoneclient.httpclient. This tests that keystoneclient.client - # can still be used. - - from keystoneclient import client - - # These statements will raise an AttributeError if the symbol isn't - # defined in the module. - - client.HTTPClient - - -class BasicRequestTests(utils.TestCase): - - url = 'http://keystone.test.com/' - - def setUp(self): - super(BasicRequestTests, self).setUp() - self.logger_message = six.moves.cStringIO() - handler = logging.StreamHandler(self.logger_message) - handler.setLevel(logging.DEBUG) - - self.logger = logging.getLogger(session.__name__) - level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.DEBUG) - self.logger.addHandler(handler) - - self.addCleanup(self.logger.removeHandler, handler) - self.addCleanup(self.logger.setLevel, level) - - def request(self, method='GET', response='Test Response', status_code=200, - url=None, headers={}, **kwargs): - if not url: - url = self.url - - self.requests_mock.register_uri(method, url, text=response, - status_code=status_code, - headers=headers) - - with self.deprecations.expect_deprecations_here(): - return httpclient.request(url, method, headers=headers, **kwargs) - - def test_basic_params(self): - method = 'GET' - response = 'Test Response' - status = 200 - - self.request(method=method, status_code=status, response=response, - headers={'Content-Type': 'application/json'}) - - self.assertEqual(self.requests_mock.last_request.method, method) - - logger_message = self.logger_message.getvalue() - - self.assertThat(logger_message, matchers.Contains('curl')) - self.assertThat(logger_message, matchers.Contains('-X %s' % - method)) - self.assertThat(logger_message, matchers.Contains(self.url)) - - self.assertThat(logger_message, matchers.Contains(str(status))) - self.assertThat(logger_message, matchers.Contains(response)) - - def test_headers(self): - headers = {'key': 'val', 'test': 'other'} - - self.request(headers=headers) - - for k, v in headers.items(): - self.assertRequestHeaderEqual(k, v) - - for header in headers.items(): - self.assertThat(self.logger_message.getvalue(), - matchers.Contains('-H "%s: %s"' % header)) - - def test_body(self): - data = "BODY DATA" - self.request(response=data, - headers={'Content-Type': 'application/json'}) - logger_message = self.logger_message.getvalue() - self.assertThat(logger_message, matchers.Contains('BODY:')) - self.assertThat(logger_message, matchers.Contains(data)) diff --git a/keystoneclient/tests/unit/test_https.py b/keystoneclient/tests/unit/test_https.py deleted file mode 100644 index 4e8d260c..00000000 --- a/keystoneclient/tests/unit/test_https.py +++ /dev/null @@ -1,106 +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. - -import mock -import requests - -from keystoneclient import httpclient -from keystoneclient.tests.unit import utils - - -FAKE_RESPONSE = utils.test_response(json={'hi': 'there'}) - -REQUEST_URL = 'https://127.0.0.1:5000/hi' -RESPONSE_BODY = '{"hi": "there"}' - - -def get_client(): - cl = httpclient.HTTPClient(username="username", password="password", - project_id="tenant", auth_url="auth_test", - cacert="ca.pem", cert=('cert.pem', "key.pem")) - return cl - - -def get_authed_client(): - cl = get_client() - cl.management_url = "https://127.0.0.1:5000" - cl.auth_token = "token" - return cl - - -class ClientTest(utils.TestCase): - - @mock.patch.object(requests, 'request') - def test_get(self, MOCK_REQUEST): - MOCK_REQUEST.return_value = FAKE_RESPONSE - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - with self.deprecations.expect_deprecations_here(): - resp, body = cl.get("/hi") - - # this may become too tightly couple later - mock_args, mock_kwargs = MOCK_REQUEST.call_args - - self.assertEqual(mock_args[0], 'GET') - self.assertEqual(mock_args[1], REQUEST_URL) - self.assertEqual(mock_kwargs['headers']['X-Auth-Token'], 'token') - self.assertEqual(mock_kwargs['cert'], ('cert.pem', 'key.pem')) - self.assertEqual(mock_kwargs['verify'], 'ca.pem') - - # Automatic JSON parsing - self.assertEqual(body, {"hi": "there"}) - - @mock.patch.object(requests, 'request') - def test_post(self, MOCK_REQUEST): - MOCK_REQUEST.return_value = FAKE_RESPONSE - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - with self.deprecations.expect_deprecations_here(): - cl.post("/hi", body=[1, 2, 3]) - - # this may become too tightly couple later - mock_args, mock_kwargs = MOCK_REQUEST.call_args - - self.assertEqual(mock_args[0], 'POST') - self.assertEqual(mock_args[1], REQUEST_URL) - self.assertEqual(mock_kwargs['data'], '[1, 2, 3]') - self.assertEqual(mock_kwargs['headers']['X-Auth-Token'], 'token') - self.assertEqual(mock_kwargs['cert'], ('cert.pem', 'key.pem')) - self.assertEqual(mock_kwargs['verify'], 'ca.pem') - - @mock.patch.object(requests, 'request') - def test_post_auth(self, MOCK_REQUEST): - MOCK_REQUEST.return_value = FAKE_RESPONSE - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient( - username="username", password="password", project_id="tenant", - auth_url="auth_test", cacert="ca.pem", - cert=('cert.pem', 'key.pem')) - cl.management_url = "https://127.0.0.1:5000" - cl.auth_token = "token" - with self.deprecations.expect_deprecations_here(): - cl.post("/hi", body=[1, 2, 3]) - - # this may become too tightly couple later - mock_args, mock_kwargs = MOCK_REQUEST.call_args - - self.assertEqual(mock_args[0], 'POST') - self.assertEqual(mock_args[1], REQUEST_URL) - self.assertEqual(mock_kwargs['data'], '[1, 2, 3]') - self.assertEqual(mock_kwargs['headers']['X-Auth-Token'], 'token') - self.assertEqual(mock_kwargs['cert'], ('cert.pem', 'key.pem')) - self.assertEqual(mock_kwargs['verify'], 'ca.pem') diff --git a/keystoneclient/tests/unit/test_keyring.py b/keystoneclient/tests/unit/test_keyring.py deleted file mode 100644 index 7d30d980..00000000 --- a/keystoneclient/tests/unit/test_keyring.py +++ /dev/null @@ -1,201 +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. - -import datetime - -import mock -from oslo_utils import timeutils - -from keystoneclient import access -from keystoneclient import httpclient -from keystoneclient.tests.unit import utils -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient import utils as client_utils - -try: - import keyring # noqa - import pickle # noqa -except ImportError: - keyring = None - - -PROJECT_SCOPED_TOKEN = client_fixtures.project_scoped_token() - -# These mirror values from PROJECT_SCOPED_TOKEN -USERNAME = 'exampleuser' -AUTH_URL = 'http://public.com:5000/v2.0' -TOKEN = '04c7d5ffaeef485f9dc69c06db285bdb' - -PASSWORD = 'password' -TENANT = 'tenant' -TENANT_ID = 'tenant_id' - - -class KeyringTest(utils.TestCase): - - def setUp(self): - if keyring is None: - self.skipTest( - 'optional package keyring or pickle is not installed') - - class MemoryKeyring(keyring.backend.KeyringBackend): - """A Simple testing keyring. - - This class supports stubbing an initial password to be returned by - setting password, and allows easy password and key retrieval. Also - records if a password was retrieved. - """ - - def __init__(self): - self.key = None - self.password = None - self.fetched = False - self.get_password_called = False - self.set_password_called = False - - def supported(self): - return 1 - - def get_password(self, service, username): - self.get_password_called = True - key = username + '@' + service - # make sure we don't get passwords crossed if one is enforced. - if self.key and self.key != key: - return None - if self.password: - self.fetched = True - return self.password - - def set_password(self, service, username, password): - self.set_password_called = True - self.key = username + '@' + service - self.password = password - - super(KeyringTest, self).setUp() - self.memory_keyring = MemoryKeyring() - keyring.set_keyring(self.memory_keyring) - - def test_no_keyring_key(self): - """Test case when no keyring set. - - Ensure that if we don't have use_keyring set in the client that - the keyring is never accessed. - """ - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL) - - # stub and check that a new token is received - method = 'get_raw_token_from_identity_service' - with mock.patch.object(cl, method) as meth: - meth.return_value = (True, PROJECT_SCOPED_TOKEN) - - self.assertTrue(cl.authenticate()) - - self.assertEqual(1, meth.call_count) - - # make sure that we never touched the keyring - self.assertFalse(self.memory_keyring.get_password_called) - self.assertFalse(self.memory_keyring.set_password_called) - - def test_build_keyring_key(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL) - - keyring_key = cl._build_keyring_key(auth_url=AUTH_URL, - username=USERNAME, - tenant_name=TENANT, - tenant_id=TENANT_ID, - token=TOKEN) - - self.assertEqual(keyring_key, - '%s/%s/%s/%s/%s' % - (AUTH_URL, TENANT_ID, TENANT, TOKEN, USERNAME)) - - def test_set_and_get_keyring_expired(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) - - # set an expired token into the keyring - auth_ref = access.AccessInfo.factory(body=PROJECT_SCOPED_TOKEN) - expired = timeutils.utcnow() - datetime.timedelta(minutes=30) - auth_ref['token']['expires'] = client_utils.isotime(expired) - self.memory_keyring.password = pickle.dumps(auth_ref) - - # stub and check that a new token is received, so not using expired - method = 'get_raw_token_from_identity_service' - with mock.patch.object(cl, method) as meth: - meth.return_value = (True, PROJECT_SCOPED_TOKEN) - - self.assertTrue(cl.authenticate()) - - self.assertEqual(1, meth.call_count) - - # check that a value was returned from the keyring - self.assertTrue(self.memory_keyring.fetched) - - # check that the new token has been loaded into the keyring - new_auth_ref = pickle.loads(self.memory_keyring.password) - self.assertEqual(new_auth_ref['token']['expires'], - PROJECT_SCOPED_TOKEN['access']['token']['expires']) - - def test_get_keyring(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) - - # set an token into the keyring - auth_ref = access.AccessInfo.factory(body=PROJECT_SCOPED_TOKEN) - future = timeutils.utcnow() + datetime.timedelta(minutes=30) - auth_ref['token']['expires'] = client_utils.isotime(future) - self.memory_keyring.password = pickle.dumps(auth_ref) - - # don't stub get_raw_token so will fail if authenticate happens - - self.assertTrue(cl.authenticate()) - self.assertTrue(self.memory_keyring.fetched) - - def test_set_keyring(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) - - # stub and check that a new token is received - method = 'get_raw_token_from_identity_service' - with mock.patch.object(cl, method) as meth: - meth.return_value = (True, PROJECT_SCOPED_TOKEN) - - self.assertTrue(cl.authenticate()) - - self.assertEqual(1, meth.call_count) - - # we checked the keyring, but we didn't find anything - self.assertTrue(self.memory_keyring.get_password_called) - self.assertFalse(self.memory_keyring.fetched) - - # check that the new token has been loaded into the keyring - self.assertTrue(self.memory_keyring.set_password_called) - new_auth_ref = pickle.loads(self.memory_keyring.password) - self.assertEqual(new_auth_ref.auth_token, TOKEN) - self.assertEqual(new_auth_ref['token'], - PROJECT_SCOPED_TOKEN['access']['token']) - self.assertEqual(new_auth_ref.username, USERNAME) diff --git a/keystoneclient/tests/unit/test_session.py b/keystoneclient/tests/unit/test_session.py deleted file mode 100644 index 27d224d0..00000000 --- a/keystoneclient/tests/unit/test_session.py +++ /dev/null @@ -1,1127 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import itertools -import logging -import uuid - -import mock -from oslo_config import cfg -from oslo_config import fixture as config -from oslo_serialization import jsonutils -import requests -import six -from testtools import matchers - -from keystoneclient import adapter -from keystoneclient.auth import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import session as client_session -from keystoneclient.tests.unit import utils - - -class SessionTests(utils.TestCase): - - TEST_URL = 'http://127.0.0.1:5000/' - - def setUp(self): - super(SessionTests, self).setUp() - self.deprecations.expect_deprecations() - - def test_get(self): - session = client_session.Session() - self.stub_url('GET', text='response') - resp = session.get(self.TEST_URL) - - self.assertEqual('GET', self.requests_mock.last_request.method) - self.assertEqual(resp.text, 'response') - self.assertTrue(resp.ok) - - def test_post(self): - session = client_session.Session() - self.stub_url('POST', text='response') - resp = session.post(self.TEST_URL, json={'hello': 'world'}) - - self.assertEqual('POST', self.requests_mock.last_request.method) - self.assertEqual(resp.text, 'response') - self.assertTrue(resp.ok) - self.assertRequestBodyIs(json={'hello': 'world'}) - - def test_head(self): - session = client_session.Session() - self.stub_url('HEAD') - resp = session.head(self.TEST_URL) - - self.assertEqual('HEAD', self.requests_mock.last_request.method) - self.assertTrue(resp.ok) - self.assertRequestBodyIs('') - - def test_put(self): - session = client_session.Session() - self.stub_url('PUT', text='response') - resp = session.put(self.TEST_URL, json={'hello': 'world'}) - - self.assertEqual('PUT', self.requests_mock.last_request.method) - self.assertEqual(resp.text, 'response') - self.assertTrue(resp.ok) - self.assertRequestBodyIs(json={'hello': 'world'}) - - def test_delete(self): - session = client_session.Session() - self.stub_url('DELETE', text='response') - resp = session.delete(self.TEST_URL) - - self.assertEqual('DELETE', self.requests_mock.last_request.method) - self.assertTrue(resp.ok) - self.assertEqual(resp.text, 'response') - - def test_patch(self): - session = client_session.Session() - self.stub_url('PATCH', text='response') - resp = session.patch(self.TEST_URL, json={'hello': 'world'}) - - self.assertEqual('PATCH', self.requests_mock.last_request.method) - self.assertTrue(resp.ok) - self.assertEqual(resp.text, 'response') - self.assertRequestBodyIs(json={'hello': 'world'}) - - def test_user_agent(self): - session = client_session.Session(user_agent='test-agent') - self.stub_url('GET', text='response') - resp = session.get(self.TEST_URL) - - self.assertTrue(resp.ok) - self.assertRequestHeaderEqual('User-Agent', 'test-agent') - - resp = session.get(self.TEST_URL, headers={'User-Agent': 'new-agent'}) - self.assertTrue(resp.ok) - self.assertRequestHeaderEqual('User-Agent', 'new-agent') - - resp = session.get(self.TEST_URL, headers={'User-Agent': 'new-agent'}, - user_agent='overrides-agent') - self.assertTrue(resp.ok) - self.assertRequestHeaderEqual('User-Agent', 'overrides-agent') - - def test_http_session_opts(self): - session = client_session.Session(cert='cert.pem', timeout=5, - verify='certs') - - FAKE_RESP = utils.test_response(text='resp') - RESP = mock.Mock(return_value=FAKE_RESP) - - with mock.patch.object(session.session, 'request', RESP) as mocked: - session.post(self.TEST_URL, data='value') - - mock_args, mock_kwargs = mocked.call_args - - self.assertEqual(mock_args[0], 'POST') - self.assertEqual(mock_args[1], self.TEST_URL) - self.assertEqual(mock_kwargs['data'], 'value') - self.assertEqual(mock_kwargs['cert'], 'cert.pem') - self.assertEqual(mock_kwargs['verify'], 'certs') - self.assertEqual(mock_kwargs['timeout'], 5) - - def test_not_found(self): - session = client_session.Session() - self.stub_url('GET', status_code=404) - self.assertRaises(exceptions.NotFound, session.get, self.TEST_URL) - - def test_server_error(self): - session = client_session.Session() - self.stub_url('GET', status_code=500) - self.assertRaises(exceptions.InternalServerError, - session.get, self.TEST_URL) - - def test_session_debug_output(self): - """Test request and response headers in debug logs. - - in order to redact secure headers while debug is true. - """ - session = client_session.Session(verify=False) - headers = {'HEADERA': 'HEADERVALB', - 'Content-Type': 'application/json'} - security_headers = {'Authorization': uuid.uuid4().hex, - 'X-Auth-Token': uuid.uuid4().hex, - 'X-Subject-Token': uuid.uuid4().hex, - 'X-Service-Token': uuid.uuid4().hex} - body = '{"a": "b"}' - data = '{"c": "d"}' - all_headers = dict( - itertools.chain(headers.items(), security_headers.items())) - self.stub_url('POST', text=body, headers=all_headers) - resp = session.post(self.TEST_URL, headers=all_headers, data=data) - self.assertEqual(resp.status_code, 200) - - self.assertIn('curl', self.logger.output) - self.assertIn('POST', self.logger.output) - self.assertIn('--insecure', self.logger.output) - self.assertIn(body, self.logger.output) - self.assertIn("'%s'" % data, self.logger.output) - - for k, v in headers.items(): - self.assertIn(k, self.logger.output) - self.assertIn(v, self.logger.output) - - # Assert that response headers contains actual values and - # only debug logs has been masked - for k, v in security_headers.items(): - self.assertIn('%s: {SHA1}' % k, self.logger.output) - self.assertEqual(v, resp.headers[k]) - self.assertNotIn(v, self.logger.output) - - def test_logs_failed_output(self): - """Test that output is logged even for failed requests.""" - session = client_session.Session() - body = {uuid.uuid4().hex: uuid.uuid4().hex} - - self.stub_url('GET', json=body, status_code=400, - headers={'Content-Type': 'application/json'}) - resp = session.get(self.TEST_URL, raise_exc=False) - - self.assertEqual(resp.status_code, 400) - self.assertIn(list(body.keys())[0], self.logger.output) - self.assertIn(list(body.values())[0], self.logger.output) - - def test_logging_body_only_for_specified_content_types(self): - """Verify response body is only logged in specific content types. - - Response bodies are logged only when the response's Content-Type header - is set to application/json. This prevents us to get an unexpected - MemoryError when reading arbitrary responses, such as streams. - """ - OMITTED_BODY = ('Omitted, Content-Type is set to %s. Only ' - 'application/json responses have their bodies logged.') - session = client_session.Session(verify=False) - - # Content-Type is not set - body = jsonutils.dumps({'token': {'id': '...'}}) - self.stub_url('POST', text=body) - session.post(self.TEST_URL) - self.assertNotIn(body, self.logger.output) - self.assertIn(OMITTED_BODY % None, self.logger.output) - - # Content-Type is set to text/xml - body = '...' - self.stub_url('POST', text=body, headers={'Content-Type': 'text/xml'}) - session.post(self.TEST_URL) - self.assertNotIn(body, self.logger.output) - self.assertIn(OMITTED_BODY % 'text/xml', self.logger.output) - - # Content-Type is set to application/json - body = jsonutils.dumps({'token': {'id': '...'}}) - self.stub_url('POST', text=body, - headers={'Content-Type': 'application/json'}) - session.post(self.TEST_URL) - self.assertIn(body, self.logger.output) - self.assertNotIn(OMITTED_BODY % 'application/json', self.logger.output) - - # Content-Type is set to application/json; charset=UTF-8 - body = jsonutils.dumps({'token': {'id': '...'}}) - self.stub_url( - 'POST', text=body, - headers={'Content-Type': 'application/json; charset=UTF-8'}) - session.post(self.TEST_URL) - self.assertIn(body, self.logger.output) - self.assertNotIn(OMITTED_BODY % 'application/json; charset=UTF-8', - self.logger.output) - - def test_unicode_data_in_debug_output(self): - """Verify that ascii-encodable data is logged without modification.""" - session = client_session.Session(verify=False) - - body = 'RESP' - data = u'αβγδ' - self.stub_url('POST', text=body) - session.post(self.TEST_URL, data=data) - - self.assertIn("'%s'" % data, self.logger.output) - - def test_binary_data_not_in_debug_output(self): - """Verify that non-ascii-encodable data causes replacement.""" - if six.PY2: - data = "my data" + chr(255) - else: - # Python 3 logging handles binary data well. - return - - session = client_session.Session(verify=False) - - body = 'RESP' - self.stub_url('POST', text=body) - - # Forced mixed unicode and byte strings in request - # elements to make sure that all joins are appropriately - # handled (any join of unicode and byte strings should - # raise a UnicodeDecodeError) - session.post(unicode(self.TEST_URL), data=data) - - self.assertNotIn('my data', self.logger.output) - - def test_logging_cacerts(self): - path_to_certs = '/path/to/certs' - session = client_session.Session(verify=path_to_certs) - - self.stub_url('GET', text='text') - session.get(self.TEST_URL) - - self.assertIn('--cacert', self.logger.output) - self.assertIn(path_to_certs, self.logger.output) - - def test_connect_retries(self): - - def _timeout_error(request, context): - raise requests.exceptions.Timeout() - - self.stub_url('GET', text=_timeout_error) - - session = client_session.Session() - retries = 3 - - with mock.patch('time.sleep') as m: - self.assertRaises(exceptions.RequestTimeout, - session.get, - self.TEST_URL, connect_retries=retries) - - self.assertEqual(retries, m.call_count) - # 3 retries finishing with 2.0 means 0.5, 1.0 and 2.0 - m.assert_called_with(2.0) - - # we count retries so there will be one initial request + 3 retries - self.assertThat(self.requests_mock.request_history, - matchers.HasLength(retries + 1)) - - def test_uses_tcp_keepalive_by_default(self): - session = client_session.Session() - requests_session = session.session - self.assertIsInstance(requests_session.adapters['http://'], - client_session.TCPKeepAliveAdapter) - self.assertIsInstance(requests_session.adapters['https://'], - client_session.TCPKeepAliveAdapter) - - def test_does_not_set_tcp_keepalive_on_custom_sessions(self): - mock_session = mock.Mock() - client_session.Session(session=mock_session) - self.assertFalse(mock_session.mount.called) - - def test_ssl_error_message(self): - error = uuid.uuid4().hex - - def _ssl_error(request, context): - raise requests.exceptions.SSLError(error) - - self.stub_url('GET', text=_ssl_error) - session = client_session.Session() - - # The exception should contain the URL and details about the SSL error - msg = _('SSL exception connecting to %(url)s: %(error)s') % { - 'url': self.TEST_URL, 'error': error} - six.assertRaisesRegex(self, - exceptions.SSLError, - msg, - session.get, - self.TEST_URL) - - def test_mask_password_in_http_log_response(self): - session = client_session.Session() - - def fake_debug(msg): - self.assertNotIn('verybadpass', msg) - - logger = mock.Mock(isEnabledFor=mock.Mock(return_value=True)) - logger.debug = mock.Mock(side_effect=fake_debug) - body = { - "connection_info": { - "driver_volume_type": "iscsi", - "data": { - "auth_password": "verybadpass", - "target_discovered": False, - "encrypted": False, - "qos_specs": None, - "target_iqn": ("iqn.2010-10.org.openstack:volume-" - "744d2085-8e78-40a5-8659-ef3cffb2480e"), - "target_portal": "172.99.69.228:3260", - "volume_id": "744d2085-8e78-40a5-8659-ef3cffb2480e", - "target_lun": 1, - "access_mode": "rw", - "auth_username": "verybadusername", - "auth_method": "CHAP"}}} - body_json = jsonutils.dumps(body) - response = mock.Mock(text=body_json, status_code=200, - headers={'content-type': 'application/json'}) - session._http_log_response(response, logger) - self.assertEqual(1, logger.debug.call_count) - - -class TCPKeepAliveAdapter(utils.TestCase): - - @mock.patch.object(client_session, 'socket') - @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') - def test_init_poolmanager_all_options(self, mock_parent_init_poolmanager, - mock_socket): - # properties expected to be in socket. - mock_socket.TCP_KEEPIDLE = mock.sentinel.TCP_KEEPIDLE - mock_socket.TCP_KEEPCNT = mock.sentinel.TCP_KEEPCNT - mock_socket.TCP_KEEPINTVL = mock.sentinel.TCP_KEEPINTVL - desired_opts = [mock_socket.TCP_KEEPIDLE, mock_socket.TCP_KEEPCNT, - mock_socket.TCP_KEEPINTVL] - - adapter = client_session.TCPKeepAliveAdapter() - adapter.init_poolmanager() - - call_args, call_kwargs = mock_parent_init_poolmanager.call_args - called_socket_opts = call_kwargs['socket_options'] - call_options = [opt for (protocol, opt, value) in called_socket_opts] - for opt in desired_opts: - self.assertIn(opt, call_options) - - @mock.patch.object(client_session, 'socket') - @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') - def test_init_poolmanager(self, mock_parent_init_poolmanager, mock_socket): - spec = ['IPPROTO_TCP', 'TCP_NODELAY', 'SOL_SOCKET', 'SO_KEEPALIVE'] - mock_socket.mock_add_spec(spec) - adapter = client_session.TCPKeepAliveAdapter() - adapter.init_poolmanager() - - call_args, call_kwargs = mock_parent_init_poolmanager.call_args - called_socket_opts = call_kwargs['socket_options'] - call_options = [opt for (protocol, opt, value) in called_socket_opts] - self.assertEqual([mock_socket.TCP_NODELAY, mock_socket.SO_KEEPALIVE], - call_options) - - -class RedirectTests(utils.TestCase): - - REDIRECT_CHAIN = ['http://myhost:3445/', - 'http://anotherhost:6555/', - 'http://thirdhost/', - 'http://finaldestination:55/'] - - DEFAULT_REDIRECT_BODY = 'Redirect' - DEFAULT_RESP_BODY = 'Found' - - def setUp(self): - super(RedirectTests, self).setUp() - self.deprecations.expect_deprecations() - - def setup_redirects(self, method='GET', status_code=305, - redirect_kwargs=None, final_kwargs=None): - redirect_kwargs = redirect_kwargs or {} - final_kwargs = final_kwargs or {} - redirect_kwargs.setdefault('text', self.DEFAULT_REDIRECT_BODY) - - for s, d in zip(self.REDIRECT_CHAIN, self.REDIRECT_CHAIN[1:]): - self.requests_mock.register_uri(method, s, status_code=status_code, - headers={'Location': d}, - **redirect_kwargs) - - final_kwargs.setdefault('status_code', 200) - final_kwargs.setdefault('text', self.DEFAULT_RESP_BODY) - self.requests_mock.register_uri(method, self.REDIRECT_CHAIN[-1], - **final_kwargs) - - def assertResponse(self, resp): - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.text, self.DEFAULT_RESP_BODY) - - def test_basic_get(self): - session = client_session.Session() - self.setup_redirects() - resp = session.get(self.REDIRECT_CHAIN[-2]) - self.assertResponse(resp) - - def test_basic_post_keeps_correct_method(self): - session = client_session.Session() - self.setup_redirects(method='POST', status_code=301) - resp = session.post(self.REDIRECT_CHAIN[-2]) - self.assertResponse(resp) - - def test_redirect_forever(self): - session = client_session.Session(redirect=True) - self.setup_redirects() - resp = session.get(self.REDIRECT_CHAIN[0]) - self.assertResponse(resp) - self.assertTrue(len(resp.history), len(self.REDIRECT_CHAIN)) - - def test_no_redirect(self): - session = client_session.Session(redirect=False) - self.setup_redirects() - resp = session.get(self.REDIRECT_CHAIN[0]) - self.assertEqual(resp.status_code, 305) - self.assertEqual(resp.url, self.REDIRECT_CHAIN[0]) - - def test_redirect_limit(self): - self.setup_redirects() - for i in (1, 2): - session = client_session.Session(redirect=i) - resp = session.get(self.REDIRECT_CHAIN[0]) - self.assertEqual(resp.status_code, 305) - self.assertEqual(resp.url, self.REDIRECT_CHAIN[i]) - self.assertEqual(resp.text, self.DEFAULT_REDIRECT_BODY) - - def test_history_matches_requests(self): - self.setup_redirects(status_code=301) - session = client_session.Session(redirect=True) - req_resp = requests.get(self.REDIRECT_CHAIN[0], - allow_redirects=True) - - ses_resp = session.get(self.REDIRECT_CHAIN[0]) - - self.assertEqual(len(req_resp.history), len(ses_resp.history)) - - for r, s in zip(req_resp.history, ses_resp.history): - self.assertEqual(r.url, s.url) - self.assertEqual(r.status_code, s.status_code) - - -class ConstructSessionFromArgsTests(utils.TestCase): - - KEY = 'keyfile' - CERT = 'certfile' - CACERT = 'cacert-path' - - def _s(self, k=None, **kwargs): - k = k or kwargs - with self.deprecations.expect_deprecations_here(): - return client_session.Session.construct(k) - - def test_verify(self): - self.assertFalse(self._s(insecure=True).verify) - self.assertTrue(self._s(verify=True, insecure=True).verify) - self.assertFalse(self._s(verify=False, insecure=True).verify) - self.assertEqual(self._s(cacert=self.CACERT).verify, self.CACERT) - - def test_cert(self): - tup = (self.CERT, self.KEY) - self.assertEqual(self._s(cert=tup).cert, tup) - self.assertEqual(self._s(cert=self.CERT, key=self.KEY).cert, tup) - self.assertIsNone(self._s(key=self.KEY).cert) - - def test_pass_through(self): - value = 42 # only a number because timeout needs to be - for key in ['timeout', 'session', 'original_ip', 'user_agent']: - args = {key: value} - self.assertEqual(getattr(self._s(args), key), value) - self.assertNotIn(key, args) - - -class AuthPlugin(base.BaseAuthPlugin): - """Very simple debug authentication plugin. - - Takes Parameters such that it can throw exceptions at the right times. - """ - - TEST_TOKEN = utils.TestCase.TEST_TOKEN - TEST_USER_ID = 'aUser' - TEST_PROJECT_ID = 'aProject' - - SERVICE_URLS = { - 'identity': {'public': 'http://identity-public:1111/v2.0', - 'admin': 'http://identity-admin:1111/v2.0'}, - 'compute': {'public': 'http://compute-public:2222/v1.0', - 'admin': 'http://compute-admin:2222/v1.0'}, - 'image': {'public': 'http://image-public:3333/v2.0', - 'admin': 'http://image-admin:3333/v2.0'} - } - - def __init__(self, token=TEST_TOKEN, invalidate=True): - self.token = token - self._invalidate = invalidate - - def get_token(self, session): - return self.token - - def get_endpoint(self, session, service_type=None, interface=None, - **kwargs): - try: - return self.SERVICE_URLS[service_type][interface] - except (KeyError, AttributeError): - return None - - def invalidate(self): - return self._invalidate - - def get_user_id(self, session): - return self.TEST_USER_ID - - def get_project_id(self, session): - return self.TEST_PROJECT_ID - - -class CalledAuthPlugin(base.BaseAuthPlugin): - - ENDPOINT = 'http://fakeendpoint/' - - def __init__(self, invalidate=True): - self.get_token_called = False - self.get_endpoint_called = False - self.endpoint_arguments = {} - self.invalidate_called = False - self._invalidate = invalidate - - def get_token(self, session): - self.get_token_called = True - return utils.TestCase.TEST_TOKEN - - def get_endpoint(self, session, **kwargs): - self.get_endpoint_called = True - self.endpoint_arguments = kwargs - return self.ENDPOINT - - def invalidate(self): - self.invalidate_called = True - return self._invalidate - - -class SessionAuthTests(utils.TestCase): - - TEST_URL = 'http://127.0.0.1:5000/' - TEST_JSON = {'hello': 'world'} - - def setUp(self): - super(SessionAuthTests, self).setUp() - self.deprecations.expect_deprecations() - - def stub_service_url(self, service_type, interface, path, - method='GET', **kwargs): - base_url = AuthPlugin.SERVICE_URLS[service_type][interface] - uri = "%s/%s" % (base_url.rstrip('/'), path.lstrip('/')) - - self.requests_mock.register_uri(method, uri, **kwargs) - - def test_auth_plugin_default_with_plugin(self): - self.stub_url('GET', base_url=self.TEST_URL, json=self.TEST_JSON) - - # if there is an auth_plugin then it should default to authenticated - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - resp = sess.get(self.TEST_URL) - self.assertEqual(resp.json(), self.TEST_JSON) - - self.assertRequestHeaderEqual('X-Auth-Token', AuthPlugin.TEST_TOKEN) - - def test_auth_plugin_disable(self): - self.stub_url('GET', base_url=self.TEST_URL, json=self.TEST_JSON) - - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - resp = sess.get(self.TEST_URL, authenticated=False) - self.assertEqual(resp.json(), self.TEST_JSON) - - self.assertRequestHeaderEqual('X-Auth-Token', None) - - def test_service_type_urls(self): - service_type = 'compute' - interface = 'public' - path = '/instances' - status = 200 - body = 'SUCCESS' - - self.stub_service_url(service_type=service_type, - interface=interface, - path=path, - status_code=status, - text=body) - - sess = client_session.Session(auth=AuthPlugin()) - resp = sess.get(path, - endpoint_filter={'service_type': service_type, - 'interface': interface}) - - self.assertEqual(self.requests_mock.last_request.url, - AuthPlugin.SERVICE_URLS['compute']['public'] + path) - self.assertEqual(resp.text, body) - self.assertEqual(resp.status_code, status) - - def test_service_url_raises_if_no_auth_plugin(self): - sess = client_session.Session() - self.assertRaises(exceptions.MissingAuthPlugin, - sess.get, '/path', - endpoint_filter={'service_type': 'compute', - 'interface': 'public'}) - - def test_service_url_raises_if_no_url_returned(self): - sess = client_session.Session(auth=AuthPlugin()) - self.assertRaises(exceptions.EndpointNotFound, - sess.get, '/path', - endpoint_filter={'service_type': 'unknown', - 'interface': 'public'}) - - def test_raises_exc_only_when_asked(self): - # A request that returns a HTTP error should by default raise an - # exception by default, if you specify raise_exc=False then it will not - self.requests_mock.get(self.TEST_URL, status_code=401) - - sess = client_session.Session() - self.assertRaises(exceptions.Unauthorized, sess.get, self.TEST_URL) - - resp = sess.get(self.TEST_URL, raise_exc=False) - self.assertEqual(401, resp.status_code) - - def test_passed_auth_plugin(self): - passed = CalledAuthPlugin() - sess = client_session.Session() - - self.requests_mock.get(CalledAuthPlugin.ENDPOINT + 'path', - status_code=200) - endpoint_filter = {'service_type': 'identity'} - - # no plugin with authenticated won't work - self.assertRaises(exceptions.MissingAuthPlugin, sess.get, 'path', - authenticated=True) - - # no plugin with an endpoint filter won't work - self.assertRaises(exceptions.MissingAuthPlugin, sess.get, 'path', - authenticated=False, endpoint_filter=endpoint_filter) - - resp = sess.get('path', auth=passed, endpoint_filter=endpoint_filter) - - self.assertEqual(200, resp.status_code) - self.assertTrue(passed.get_endpoint_called) - self.assertTrue(passed.get_token_called) - - def test_passed_auth_plugin_overrides(self): - fixed = CalledAuthPlugin() - passed = CalledAuthPlugin() - - sess = client_session.Session(fixed) - - self.requests_mock.get(CalledAuthPlugin.ENDPOINT + 'path', - status_code=200) - - resp = sess.get('path', auth=passed, - endpoint_filter={'service_type': 'identity'}) - - self.assertEqual(200, resp.status_code) - self.assertTrue(passed.get_endpoint_called) - self.assertTrue(passed.get_token_called) - self.assertFalse(fixed.get_endpoint_called) - self.assertFalse(fixed.get_token_called) - - def test_requests_auth_plugin(self): - sess = client_session.Session() - - requests_auth = object() - - FAKE_RESP = utils.test_response(text='resp') - RESP = mock.Mock(return_value=FAKE_RESP) - - with mock.patch.object(sess.session, 'request', RESP) as mocked: - sess.get(self.TEST_URL, requests_auth=requests_auth) - - mocked.assert_called_once_with('GET', self.TEST_URL, - headers=mock.ANY, - allow_redirects=mock.ANY, - auth=requests_auth, - verify=mock.ANY) - - def test_reauth_called(self): - auth = CalledAuthPlugin(invalidate=True) - sess = client_session.Session(auth=auth) - - self.requests_mock.get(self.TEST_URL, - [{'text': 'Failed', 'status_code': 401}, - {'text': 'Hello', 'status_code': 200}]) - - # allow_reauth=True is the default - resp = sess.get(self.TEST_URL, authenticated=True) - - self.assertEqual(200, resp.status_code) - self.assertEqual('Hello', resp.text) - self.assertTrue(auth.invalidate_called) - - def test_reauth_not_called(self): - auth = CalledAuthPlugin(invalidate=True) - sess = client_session.Session(auth=auth) - - self.requests_mock.get(self.TEST_URL, - [{'text': 'Failed', 'status_code': 401}, - {'text': 'Hello', 'status_code': 200}]) - - self.assertRaises(exceptions.Unauthorized, sess.get, self.TEST_URL, - authenticated=True, allow_reauth=False) - self.assertFalse(auth.invalidate_called) - - def test_endpoint_override_overrides_filter(self): - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - - override_base = 'http://mytest/' - path = 'path' - override_url = override_base + path - resp_text = uuid.uuid4().hex - - self.requests_mock.get(override_url, text=resp_text) - - resp = sess.get(path, - endpoint_override=override_base, - endpoint_filter={'service_type': 'identity'}) - - self.assertEqual(resp_text, resp.text) - self.assertEqual(override_url, self.requests_mock.last_request.url) - - self.assertTrue(auth.get_token_called) - self.assertFalse(auth.get_endpoint_called) - - def test_endpoint_override_ignore_full_url(self): - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - - path = 'path' - url = self.TEST_URL + path - - resp_text = uuid.uuid4().hex - self.requests_mock.get(url, text=resp_text) - - resp = sess.get(url, - endpoint_override='http://someother.url', - endpoint_filter={'service_type': 'identity'}) - - self.assertEqual(resp_text, resp.text) - self.assertEqual(url, self.requests_mock.last_request.url) - - self.assertTrue(auth.get_token_called) - self.assertFalse(auth.get_endpoint_called) - - def test_user_and_project_id(self): - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - - self.assertEqual(auth.TEST_USER_ID, sess.get_user_id()) - self.assertEqual(auth.TEST_PROJECT_ID, sess.get_project_id()) - - def test_logger_object_passed(self): - logger = logging.getLogger(uuid.uuid4().hex) - logger.setLevel(logging.DEBUG) - logger.propagate = False - - io = six.StringIO() - handler = logging.StreamHandler(io) - logger.addHandler(handler) - - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - response = {uuid.uuid4().hex: uuid.uuid4().hex} - - self.stub_url('GET', - json=response, - headers={'Content-Type': 'application/json'}) - - resp = sess.get(self.TEST_URL, logger=logger) - - self.assertEqual(response, resp.json()) - output = io.getvalue() - - self.assertIn(self.TEST_URL, output) - self.assertIn(list(response.keys())[0], output) - self.assertIn(list(response.values())[0], output) - - self.assertNotIn(self.TEST_URL, self.logger.output) - self.assertNotIn(list(response.keys())[0], self.logger.output) - self.assertNotIn(list(response.values())[0], self.logger.output) - - -class AdapterTest(utils.TestCase): - - SERVICE_TYPE = uuid.uuid4().hex - SERVICE_NAME = uuid.uuid4().hex - INTERFACE = uuid.uuid4().hex - REGION_NAME = uuid.uuid4().hex - USER_AGENT = uuid.uuid4().hex - VERSION = uuid.uuid4().hex - - TEST_URL = CalledAuthPlugin.ENDPOINT - - def setUp(self): - super(AdapterTest, self).setUp() - self.deprecations.expect_deprecations() - - def _create_loaded_adapter(self): - auth = CalledAuthPlugin() - sess = client_session.Session() - return adapter.Adapter(sess, - auth=auth, - service_type=self.SERVICE_TYPE, - service_name=self.SERVICE_NAME, - interface=self.INTERFACE, - region_name=self.REGION_NAME, - user_agent=self.USER_AGENT, - version=self.VERSION) - - def _verify_endpoint_called(self, adpt): - self.assertEqual(self.SERVICE_TYPE, - adpt.auth.endpoint_arguments['service_type']) - self.assertEqual(self.SERVICE_NAME, - adpt.auth.endpoint_arguments['service_name']) - self.assertEqual(self.INTERFACE, - adpt.auth.endpoint_arguments['interface']) - self.assertEqual(self.REGION_NAME, - adpt.auth.endpoint_arguments['region_name']) - self.assertEqual(self.VERSION, - adpt.auth.endpoint_arguments['version']) - - def test_setting_variables_on_request(self): - response = uuid.uuid4().hex - self.stub_url('GET', text=response) - adpt = self._create_loaded_adapter() - resp = adpt.get('/') - self.assertEqual(resp.text, response) - - self._verify_endpoint_called(adpt) - self.assertTrue(adpt.auth.get_token_called) - self.assertRequestHeaderEqual('User-Agent', self.USER_AGENT) - - def test_setting_variables_on_get_endpoint(self): - adpt = self._create_loaded_adapter() - url = adpt.get_endpoint() - - self.assertEqual(self.TEST_URL, url) - self._verify_endpoint_called(adpt) - - def test_legacy_binding(self): - key = uuid.uuid4().hex - val = uuid.uuid4().hex - response = jsonutils.dumps({key: val}) - - self.stub_url('GET', text=response) - - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.LegacyJsonAdapter(sess, - service_type=self.SERVICE_TYPE, - user_agent=self.USER_AGENT) - - resp, body = adpt.get('/') - self.assertEqual(self.SERVICE_TYPE, - auth.endpoint_arguments['service_type']) - self.assertEqual(resp.text, response) - self.assertEqual(val, body[key]) - - def test_legacy_binding_non_json_resp(self): - response = uuid.uuid4().hex - self.stub_url('GET', text=response, - headers={'Content-Type': 'text/html'}) - - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.LegacyJsonAdapter(sess, - service_type=self.SERVICE_TYPE, - user_agent=self.USER_AGENT) - - resp, body = adpt.get('/') - self.assertEqual(self.SERVICE_TYPE, - auth.endpoint_arguments['service_type']) - self.assertEqual(resp.text, response) - self.assertIsNone(body) - - def test_methods(self): - sess = client_session.Session() - adpt = adapter.Adapter(sess) - url = 'http://url' - - for method in ['get', 'head', 'post', 'put', 'patch', 'delete']: - with mock.patch.object(adpt, 'request') as m: - getattr(adpt, method)(url) - m.assert_called_once_with(url, method.upper()) - - def test_setting_endpoint_override(self): - endpoint_override = 'http://overrideurl' - path = '/path' - endpoint_url = endpoint_override + path - - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.Adapter(sess, endpoint_override=endpoint_override) - - response = uuid.uuid4().hex - self.requests_mock.get(endpoint_url, text=response) - - resp = adpt.get(path) - - self.assertEqual(response, resp.text) - self.assertEqual(endpoint_url, self.requests_mock.last_request.url) - - self.assertEqual(endpoint_override, adpt.get_endpoint()) - - def test_adapter_invalidate(self): - auth = CalledAuthPlugin() - sess = client_session.Session() - adpt = adapter.Adapter(sess, auth=auth) - - adpt.invalidate() - - self.assertTrue(auth.invalidate_called) - - def test_adapter_get_token(self): - auth = CalledAuthPlugin() - sess = client_session.Session() - adpt = adapter.Adapter(sess, auth=auth) - - self.assertEqual(self.TEST_TOKEN, adpt.get_token()) - self.assertTrue(auth.get_token_called) - - def test_adapter_connect_retries(self): - retries = 2 - sess = client_session.Session() - adpt = adapter.Adapter(sess, connect_retries=retries) - - def _refused_error(request, context): - raise requests.exceptions.ConnectionError() - - self.stub_url('GET', text=_refused_error) - - with mock.patch('time.sleep') as m: - self.assertRaises(exceptions.ConnectionRefused, - adpt.get, self.TEST_URL) - self.assertEqual(retries, m.call_count) - - # we count retries so there will be one initial request + 2 retries - self.assertThat(self.requests_mock.request_history, - matchers.HasLength(retries + 1)) - - def test_user_and_project_id(self): - auth = AuthPlugin() - sess = client_session.Session() - adpt = adapter.Adapter(sess, auth=auth) - - self.assertEqual(auth.TEST_USER_ID, adpt.get_user_id()) - self.assertEqual(auth.TEST_PROJECT_ID, adpt.get_project_id()) - - def test_logger_object_passed(self): - logger = logging.getLogger(uuid.uuid4().hex) - logger.setLevel(logging.DEBUG) - logger.propagate = False - - io = six.StringIO() - handler = logging.StreamHandler(io) - logger.addHandler(handler) - - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.Adapter(sess, auth=auth, logger=logger) - - response = {uuid.uuid4().hex: uuid.uuid4().hex} - - self.stub_url('GET', json=response, - headers={'Content-Type': 'application/json'}) - - resp = adpt.get(self.TEST_URL, logger=logger) - - self.assertEqual(response, resp.json()) - output = io.getvalue() - - self.assertIn(self.TEST_URL, output) - self.assertIn(list(response.keys())[0], output) - self.assertIn(list(response.values())[0], output) - - self.assertNotIn(self.TEST_URL, self.logger.output) - self.assertNotIn(list(response.keys())[0], self.logger.output) - self.assertNotIn(list(response.values())[0], self.logger.output) - - -class ConfLoadingTests(utils.TestCase): - - GROUP = 'sessiongroup' - - def setUp(self): - super(ConfLoadingTests, self).setUp() - - self.conf_fixture = self.useFixture(config.Config()) - client_session.Session.register_conf_options(self.conf_fixture.conf, - self.GROUP) - - def config(self, **kwargs): - kwargs['group'] = self.GROUP - self.conf_fixture.config(**kwargs) - - def get_session(self, **kwargs): - with self.deprecations.expect_deprecations_here(): - return client_session.Session.load_from_conf_options( - self.conf_fixture.conf, - self.GROUP, - **kwargs) - - def test_insecure_timeout(self): - self.config(insecure=True, timeout=5) - s = self.get_session() - - self.assertFalse(s.verify) - self.assertEqual(5, s.timeout) - - def test_client_certs(self): - cert = '/path/to/certfile' - key = '/path/to/keyfile' - - self.config(certfile=cert, keyfile=key) - s = self.get_session() - - self.assertTrue(s.verify) - self.assertEqual((cert, key), s.cert) - - def test_cacert(self): - cafile = '/path/to/cacert' - - self.config(cafile=cafile) - s = self.get_session() - - self.assertEqual(cafile, s.verify) - - def test_deprecated(self): - def new_deprecated(): - return cfg.DeprecatedOpt(uuid.uuid4().hex, group=uuid.uuid4().hex) - - opt_names = ['cafile', 'certfile', 'keyfile', 'insecure', 'timeout'] - depr = dict([(n, [new_deprecated()]) for n in opt_names]) - opts = client_session.Session.get_conf_options(deprecated_opts=depr) - - self.assertThat(opt_names, matchers.HasLength(len(opts))) - for opt in opts: - self.assertIn(depr[opt.name][0], opt.deprecated_opts) - - -class CliLoadingTests(utils.TestCase): - - def setUp(self): - super(CliLoadingTests, self).setUp() - - self.parser = argparse.ArgumentParser() - client_session.Session.register_cli_options(self.parser) - - def get_session(self, val, **kwargs): - args = self.parser.parse_args(val.split()) - with self.deprecations.expect_deprecations_here(): - return client_session.Session.load_from_cli_options(args, **kwargs) - - def test_insecure_timeout(self): - s = self.get_session('--insecure --timeout 5.5') - - self.assertFalse(s.verify) - self.assertEqual(5.5, s.timeout) - - def test_client_certs(self): - cert = '/path/to/certfile' - key = '/path/to/keyfile' - - s = self.get_session('--os-cert %s --os-key %s' % (cert, key)) - - self.assertTrue(s.verify) - self.assertEqual((cert, key), s.cert) - - def test_cacert(self): - cacert = '/path/to/cacert' - - s = self.get_session('--os-cacert %s' % cacert) - - self.assertEqual(cacert, s.verify) diff --git a/keystoneclient/tests/unit/test_utils.py b/keystoneclient/tests/unit/test_utils.py deleted file mode 100644 index 01443314..00000000 --- a/keystoneclient/tests/unit/test_utils.py +++ /dev/null @@ -1,134 +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 keystoneauth1 import exceptions as ksa_exceptions -import six -import testresources -from testtools import matchers - - -from keystoneclient import exceptions as ksc_exceptions -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils as test_utils -from keystoneclient import utils - - -class FakeResource(object): - pass - - -class FakeManager(object): - - resource_class = FakeResource - - resources = { - '1234': {'name': 'entity_one'}, - '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0': {'name': 'entity_two'}, - '\xe3\x82\xbdtest': {'name': u'\u30bdtest'}, - '5678': {'name': '9876'} - } - - def get(self, resource_id): - try: - return self.resources[str(resource_id)] - except KeyError: - raise ksa_exceptions.NotFound(resource_id) - - def find(self, name=None): - if name == '9999': - # NOTE(morganfainberg): special case that raises NoUniqueMatch. - raise ksc_exceptions.NoUniqueMatch() - for resource_id, resource in self.resources.items(): - if resource['name'] == str(name): - return resource - raise ksa_exceptions.NotFound(name) - - -class FindResourceTestCase(test_utils.TestCase): - - def setUp(self): - super(FindResourceTestCase, self).setUp() - self.manager = FakeManager() - - def test_find_none(self): - self.assertRaises(ksc_exceptions.CommandError, - utils.find_resource, - self.manager, - 'asdf') - - def test_find_by_integer_id(self): - output = utils.find_resource(self.manager, 1234) - self.assertEqual(output, self.manager.resources['1234']) - - def test_find_by_str_id(self): - output = utils.find_resource(self.manager, '1234') - self.assertEqual(output, self.manager.resources['1234']) - - def test_find_by_uuid(self): - uuid = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0' - output = utils.find_resource(self.manager, uuid) - self.assertEqual(output, self.manager.resources[uuid]) - - def test_find_by_unicode(self): - name = '\xe3\x82\xbdtest' - output = utils.find_resource(self.manager, name) - self.assertEqual(output, self.manager.resources[name]) - - def test_find_by_str_name(self): - output = utils.find_resource(self.manager, 'entity_one') - self.assertEqual(output, self.manager.resources['1234']) - - def test_find_by_int_name(self): - output = utils.find_resource(self.manager, 9876) - self.assertEqual(output, self.manager.resources['5678']) - - def test_find_no_unique_match(self): - self.assertRaises(ksc_exceptions.CommandError, - utils.find_resource, - self.manager, - 9999) - - -class FakeObject(object): - def __init__(self, name): - self.name = name - - -class HashSignedTokenTestCase(test_utils.TestCase, - testresources.ResourcedTestCase): - """Unit tests for utils.hash_signed_token().""" - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_default_md5(self): - """The default hash method is md5.""" - token = self.examples.SIGNED_TOKEN_SCOPED - if six.PY3: - token = token.encode('utf-8') - token_id_default = utils.hash_signed_token(token) - token_id_md5 = utils.hash_signed_token(token, mode='md5') - self.assertThat(token_id_default, matchers.Equals(token_id_md5)) - # md5 hash is 32 chars. - self.assertThat(token_id_default, matchers.HasLength(32)) - - def test_sha256(self): - """Can also hash with sha256.""" - token = self.examples.SIGNED_TOKEN_SCOPED - if six.PY3: - token = token.encode('utf-8') - token_id = utils.hash_signed_token(token, mode='sha256') - # sha256 hash is 64 chars. - self.assertThat(token_id, matchers.HasLength(64)) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/utils.py b/keystoneclient/tests/unit/utils.py deleted file mode 100644 index 6921b4b0..00000000 --- a/keystoneclient/tests/unit/utils.py +++ /dev/null @@ -1,184 +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. - -import logging -import sys -import uuid - -import fixtures -from oslo_serialization import jsonutils -import requests -import requests_mock -from requests_mock.contrib import fixture -from six.moves.urllib import parse as urlparse -import testscenarios -import testtools - -from keystoneclient.tests.unit import client_fixtures - - -class TestCase(testtools.TestCase): - - TEST_DOMAIN_ID = uuid.uuid4().hex - TEST_DOMAIN_NAME = uuid.uuid4().hex - TEST_GROUP_ID = uuid.uuid4().hex - TEST_ROLE_ID = uuid.uuid4().hex - TEST_TENANT_ID = uuid.uuid4().hex - TEST_TENANT_NAME = uuid.uuid4().hex - TEST_TOKEN = uuid.uuid4().hex - TEST_TRUST_ID = uuid.uuid4().hex - TEST_USER = uuid.uuid4().hex - TEST_USER_ID = uuid.uuid4().hex - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - - def setUp(self): - super(TestCase, self).setUp() - self.deprecations = self.useFixture(client_fixtures.Deprecations()) - - self.logger = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG)) - self.requests_mock = self.useFixture(fixture.Fixture()) - - def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs): - if not base_url: - base_url = self.TEST_URL - - if json: - kwargs['text'] = jsonutils.dumps(json) - headers = kwargs.setdefault('headers', {}) - headers['Content-Type'] = 'application/json' - - if parts: - url = '/'.join([p.strip('/') for p in [base_url] + parts]) - else: - url = base_url - - url = url.replace("/?", "?") - self.requests_mock.register_uri(method, url, **kwargs) - - def assertRequestBodyIs(self, body=None, json=None): - last_request_body = self.requests_mock.last_request.body - if json: - val = jsonutils.loads(last_request_body) - self.assertEqual(json, val) - elif body: - self.assertEqual(body, last_request_body) - - def assertQueryStringIs(self, qs=''): - r"""Verify the QueryString matches what is expected. - - The qs parameter should be of the format \'foo=bar&abc=xyz\' - """ - expected = urlparse.parse_qs(qs, keep_blank_values=True) - parts = urlparse.urlparse(self.requests_mock.last_request.url) - querystring = urlparse.parse_qs(parts.query, keep_blank_values=True) - self.assertEqual(expected, querystring) - - def assertQueryStringContains(self, **kwargs): - """Verify the query string contains the expected parameters. - - This method is used to verify that the query string for the most recent - request made contains all the parameters provided as ``kwargs``, and - that the value of each parameter contains the value for the kwarg. If - the value for the kwarg is an empty string (''), then all that's - verified is that the parameter is present. - - """ - parts = urlparse.urlparse(self.requests_mock.last_request.url) - qs = urlparse.parse_qs(parts.query, keep_blank_values=True) - - for k, v in kwargs.items(): - self.assertIn(k, qs) - self.assertIn(v, qs[k]) - - def assertRequestHeaderEqual(self, name, val): - """Verify that the last request made contains a header and its value. - - The request must have already been made. - """ - headers = self.requests_mock.last_request.headers - self.assertEqual(headers.get(name), val) - - -def test_response(**kwargs): - r = requests.Request(method='GET', url='http://localhost:5000').prepare() - return requests_mock.create_response(r, **kwargs) - - -class DisableModuleFixture(fixtures.Fixture): - """A fixture to provide support for unloading/disabling modules.""" - - def __init__(self, module, *args, **kw): - super(DisableModuleFixture, self).__init__(*args, **kw) - self.module = module - self._finders = [] - self._cleared_modules = {} - - def tearDown(self): - super(DisableModuleFixture, self).tearDown() - for finder in self._finders: - sys.meta_path.remove(finder) - sys.modules.update(self._cleared_modules) - - def clear_module(self): - cleared_modules = {} - for fullname in list(sys.modules): - if (fullname == self.module or - fullname.startswith(self.module + '.')): - cleared_modules[fullname] = sys.modules.pop(fullname) - return cleared_modules - - def setUp(self): - """Ensure ImportError for the specified module.""" - super(DisableModuleFixture, self).setUp() - - # Clear 'module' references in sys.modules - self._cleared_modules.update(self.clear_module()) - - finder = NoModuleFinder(self.module) - self._finders.append(finder) - sys.meta_path.insert(0, finder) - - -class ClientTestCaseMixin(testscenarios.WithScenarios): - - client_fixture_class = None - data_fixture_class = None - - def setUp(self): - super(ClientTestCaseMixin, self).setUp() - - self.data_fixture = None - self.client_fixture = None - self.client = None - - if self.client_fixture_class: - fix = self.client_fixture_class(self.requests_mock, - self.deprecations) - self.client_fixture = self.useFixture(fix) - self.client = self.client_fixture.client - self.TEST_USER_ID = self.client_fixture.user_id - - if self.data_fixture_class: - fix = self.data_fixture_class(self.requests_mock) - self.data_fixture = self.useFixture(fix) - - -class NoModuleFinder(object): - """Disallow further imports of 'module'.""" - - def __init__(self, module): - self.module = module - - def find_module(self, fullname, path): - if fullname == self.module or fullname.startswith(self.module + '.'): - raise ImportError diff --git a/keystoneclient/tests/unit/v2_0/__init__.py b/keystoneclient/tests/unit/v2_0/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/v2_0/client_fixtures.py b/keystoneclient/tests/unit/v2_0/client_fixtures.py deleted file mode 100644 index 019b9445..00000000 --- a/keystoneclient/tests/unit/v2_0/client_fixtures.py +++ /dev/null @@ -1,127 +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 __future__ import unicode_literals -import uuid - -from keystoneauth1 import fixture - - -def unscoped_token(): - return fixture.V2Token(token_id='3e2813b7ba0b4006840c3825860b86ed', - expires='2012-10-03T16:58:01Z', - user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser') - - -def project_scoped_token(): - _TENANT_ID = '225da22d3ce34b15877ea70b2a575f58' - - f = fixture.V2Token(token_id='04c7d5ffaeef485f9dc69c06db285bdb', - expires='2012-10-03T16:53:36Z', - tenant_id='225da22d3ce34b15877ea70b2a575f58', - tenant_name='exampleproject', - user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser', - audit_chain_id=uuid.uuid4().hex) - - f.add_role(id='member_id', name='Member') - - s = f.add_service('volume', 'Volume Service') - s.add_endpoint(public='http://public.com:8776/v1/%s' % _TENANT_ID, - admin='http://admin:8776/v1/%s' % _TENANT_ID, - internal='http://internal:8776/v1/%s' % _TENANT_ID, - region='RegionOne') - - s = f.add_service('image', 'Image Service') - s.add_endpoint(public='http://public.com:9292/v1', - admin='http://admin:9292/v1', - internal='http://internal:9292/v1', - region='RegionOne') - - s = f.add_service('compute', 'Compute Service') - s.add_endpoint(public='http://public.com:8774/v2/%s' % _TENANT_ID, - admin='http://admin:8774/v2/%s' % _TENANT_ID, - internal='http://internal:8774/v2/%s' % _TENANT_ID, - region='RegionOne') - - s = f.add_service('ec2', 'EC2 Service') - s.add_endpoint(public='http://public.com:8773/services/Cloud', - admin='http://admin:8773/services/Admin', - internal='http://internal:8773/services/Cloud', - region='RegionOne') - - s = f.add_service('identity', 'Identity Service') - s.add_endpoint(public='http://public.com:5000/v2.0', - admin='http://admin:35357/v2.0', - internal='http://internal:5000/v2.0', - region='RegionOne') - - return f - - -def auth_response_body(): - f = fixture.V2Token(token_id='ab48a9efdfedb23ty3494', - expires='2010-11-01T03:32:15-05:00', - tenant_id='345', - tenant_name='My Project', - user_id='123', - user_name='jqsmith', - audit_chain_id=uuid.uuid4().hex) - - f.add_role(id='234', name='compute:admin') - role = f.add_role(id='235', name='object-store:admin') - role['tenantId'] = '1' - - s = f.add_service('compute', 'Cloud Servers') - endpoint = s.add_endpoint(public='https://compute.north.host/v1/1234', - internal='https://compute.north.host/v1/1234', - region='North') - endpoint['tenantId'] = '1' - endpoint['versionId'] = '1.0' - endpoint['versionInfo'] = 'https://compute.north.host/v1.0/' - endpoint['versionList'] = 'https://compute.north.host/' - - endpoint = s.add_endpoint(public='https://compute.north.host/v1.1/3456', - internal='https://compute.north.host/v1.1/3456', - region='North') - endpoint['tenantId'] = '2' - endpoint['versionId'] = '1.1' - endpoint['versionInfo'] = 'https://compute.north.host/v1.1/' - endpoint['versionList'] = 'https://compute.north.host/' - - s = f.add_service('object-store', 'Cloud Files') - endpoint = s.add_endpoint(public='https://swift.north.host/v1/blah', - internal='https://swift.north.host/v1/blah', - region='South') - endpoint['tenantId'] = '11' - endpoint['versionId'] = '1.0' - endpoint['versionInfo'] = 'uri' - endpoint['versionList'] = 'uri' - - endpoint = s.add_endpoint(public='https://swift.north.host/v1.1/blah', - internal='https://compute.north.host/v1.1/blah', - region='South') - endpoint['tenantId'] = '2' - endpoint['versionId'] = '1.1' - endpoint['versionInfo'] = 'https://swift.north.host/v1.1/' - endpoint['versionList'] = 'https://swift.north.host/' - - s = f.add_service('image', 'Image Servers') - s.add_endpoint(public='https://image.north.host/v1/', - internal='https://image-internal.north.host/v1/', - region='North') - s.add_endpoint(public='https://image.south.host/v1/', - internal='https://image-internal.south.host/v1/', - region='South') - - return f diff --git a/keystoneclient/tests/unit/v2_0/test_access.py b/keystoneclient/tests/unit/v2_0/test_access.py deleted file mode 100644 index 95556aff..00000000 --- a/keystoneclient/tests/unit/v2_0/test_access.py +++ /dev/null @@ -1,217 +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. - -import datetime -import uuid - -from keystoneauth1 import fixture -from oslo_utils import timeutils -import testresources - -from keystoneclient import access -from keystoneclient.tests.unit import client_fixtures as token_data -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils - - -class AccessInfoTest(utils.TestCase, testresources.ResourcedTestCase): - - resources = [('examples', token_data.EXAMPLES_RESOURCE)] - - def test_building_unscoped_accessinfo(self): - token = client_fixtures.unscoped_token() - auth_ref = access.AccessInfo.factory(body=token) - - self.assertTrue(auth_ref) - self.assertIn('token', auth_ref) - - self.assertEqual(auth_ref.auth_token, - '3e2813b7ba0b4006840c3825860b86ed') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') - - self.assertEqual(auth_ref.role_ids, []) - self.assertEqual(auth_ref.role_names, []) - - self.assertIsNone(auth_ref.tenant_name) - self.assertIsNone(auth_ref.tenant_id) - - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.auth_url) - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.management_url) - - with self.deprecations.expect_deprecations_here(): - self.assertFalse(auth_ref.scoped) - self.assertFalse(auth_ref.domain_scoped) - self.assertFalse(auth_ref.project_scoped) - self.assertFalse(auth_ref.trust_scoped) - - self.assertIsNone(auth_ref.project_domain_id) - self.assertIsNone(auth_ref.project_domain_name) - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - - self.assertEqual(auth_ref.expires, token.expires) - self.assertEqual(auth_ref.issued, token.issued) - - self.assertEqual(token.audit_id, auth_ref.audit_id) - self.assertIsNone(auth_ref.audit_chain_id) - self.assertIsNone(token.audit_chain_id) - - def test_will_expire_soon(self): - token = client_fixtures.unscoped_token() - expires = timeutils.utcnow() + datetime.timedelta(minutes=5) - token.expires = expires - auth_ref = access.AccessInfo.factory(body=token) - self.assertFalse(auth_ref.will_expire_soon(stale_duration=120)) - self.assertTrue(auth_ref.will_expire_soon(stale_duration=300)) - self.assertFalse(auth_ref.will_expire_soon()) - - def test_building_scoped_accessinfo(self): - token = client_fixtures.project_scoped_token() - auth_ref = access.AccessInfo.factory(body=token) - - self.assertTrue(auth_ref) - self.assertIn('token', auth_ref) - self.assertIn('serviceCatalog', auth_ref) - self.assertTrue(auth_ref['serviceCatalog']) - - self.assertEqual(auth_ref.auth_token, - '04c7d5ffaeef485f9dc69c06db285bdb') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') - - self.assertEqual(auth_ref.role_ids, ['member_id']) - self.assertEqual(auth_ref.role_names, ['Member']) - - self.assertEqual(auth_ref.tenant_name, 'exampleproject') - self.assertEqual(auth_ref.tenant_id, - '225da22d3ce34b15877ea70b2a575f58') - - self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) - self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.auth_url, - ('http://public.com:5000/v2.0',)) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.management_url, - ('http://admin:35357/v2.0',)) - - self.assertEqual(auth_ref.project_domain_id, 'default') - self.assertEqual(auth_ref.project_domain_name, 'Default') - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - - with self.deprecations.expect_deprecations_here(): - self.assertTrue(auth_ref.scoped) - self.assertTrue(auth_ref.project_scoped) - self.assertFalse(auth_ref.domain_scoped) - - self.assertEqual(token.audit_id, auth_ref.audit_id) - self.assertEqual(token.audit_chain_id, auth_ref.audit_chain_id) - - def test_diablo_token(self): - diablo_token = self.examples.TOKEN_RESPONSES[ - self.examples.VALID_DIABLO_TOKEN] - auth_ref = access.AccessInfo.factory(body=diablo_token) - - self.assertTrue(auth_ref) - self.assertEqual(auth_ref.username, 'user_name1') - self.assertEqual(auth_ref.project_id, 'tenant_id1') - self.assertEqual(auth_ref.project_name, 'tenant_id1') - self.assertEqual(auth_ref.project_domain_id, 'default') - self.assertEqual(auth_ref.project_domain_name, 'Default') - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - self.assertEqual(auth_ref.role_names, ['role1', 'role2']) - with self.deprecations.expect_deprecations_here(): - self.assertFalse(auth_ref.scoped) - - def test_grizzly_token(self): - grizzly_token = self.examples.TOKEN_RESPONSES[ - self.examples.SIGNED_TOKEN_SCOPED_KEY] - auth_ref = access.AccessInfo.factory(body=grizzly_token) - - self.assertEqual(auth_ref.project_id, 'tenant_id1') - self.assertEqual(auth_ref.project_name, 'tenant_name1') - self.assertEqual(auth_ref.project_domain_id, 'default') - self.assertEqual(auth_ref.project_domain_name, 'Default') - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - self.assertEqual(auth_ref.role_names, ['role1', 'role2']) - - def test_v2_roles(self): - role_id = 'a' - role_name = 'b' - - token = fixture.V2Token() - token.set_scope() - token.add_role(id=role_id, name=role_name) - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual([role_id], auth_ref.role_ids) - self.assertEqual([role_id], auth_ref['metadata']['roles']) - self.assertEqual([role_name], auth_ref.role_names) - self.assertEqual([{'name': role_name}], auth_ref['user']['roles']) - - def test_trusts(self): - user_id = uuid.uuid4().hex - trust_id = uuid.uuid4().hex - - token = fixture.V2Token(user_id=user_id, trust_id=trust_id) - token.set_scope() - token.add_role() - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual(trust_id, auth_ref.trust_id) - self.assertEqual(user_id, auth_ref.trustee_user_id) - - self.assertEqual(trust_id, token['access']['trust']['id']) - - def test_override_auth_token(self): - token = fixture.V2Token() - token.set_scope() - token.add_role() - - new_auth_token = uuid.uuid4().hex - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual(token.token_id, auth_ref.auth_token) - - auth_ref.auth_token = new_auth_token - self.assertEqual(new_auth_token, auth_ref.auth_token) - - del auth_ref.auth_token - self.assertEqual(token.token_id, auth_ref.auth_token) - - def test_override_auth_token_in_factory(self): - token = fixture.V2Token() - token.set_scope() - token.add_role() - - new_auth_token = uuid.uuid4().hex - - auth_ref = access.AccessInfo.factory(body=token, - auth_token=new_auth_token) - - self.assertEqual(new_auth_token, auth_ref.auth_token) - del auth_ref.auth_token - self.assertEqual(token.token_id, auth_ref.auth_token) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v2_0/test_auth.py b/keystoneclient/tests/unit/v2_0/test_auth.py deleted file mode 100644 index 64f2ea03..00000000 --- a/keystoneclient/tests/unit/v2_0/test_auth.py +++ /dev/null @@ -1,268 +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. - -import copy -import datetime - -from oslo_serialization import jsonutils -from oslo_utils import timeutils -from testtools import testcase - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client - - -class AuthenticateAgainstKeystoneTests(utils.TestCase): - def setUp(self): - super(AuthenticateAgainstKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10.000123Z", - "id": self.TEST_TOKEN, - "tenant": { - "id": self.TEST_TENANT_ID - }, - }, - "user": { - "id": self.TEST_USER - }, - "serviceCatalog": self.TEST_SERVICE_CATALOG, - }, - } - self.TEST_REQUEST_BODY = { - "auth": { - "passwordCredentials": { - "username": self.TEST_USER, - "password": self.TEST_TOKEN, - }, - "tenantId": self.TEST_TENANT_ID, - }, - } - - def test_authenticate_success_expired(self): - resp_a = copy.deepcopy(self.TEST_RESPONSE_DICT) - resp_b = copy.deepcopy(self.TEST_RESPONSE_DICT) - headers = {'Content-Type': 'application/json'} - - # Build an expired token - resp_a['access']['token']['expires'] = ( - (timeutils.utcnow() - datetime.timedelta(1)).isoformat()) - - # Build a new response - TEST_TOKEN = "abcdef" - resp_b['access']['token']['expires'] = '2020-01-01T00:00:10.000123Z' - resp_b['access']['token']['id'] = TEST_TOKEN - - # return expired first, and then the new response - self.stub_auth(response_list=[{'json': resp_a, 'headers': headers}, - {'json': resp_b, 'headers': headers}]) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_TOKEN) - - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(cs.auth_token, TEST_TOKEN) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_failure(self): - _auth = 'auth' - _cred = 'passwordCredentials' - _pass = 'password' - self.TEST_REQUEST_BODY[_auth][_cred][_pass] = 'bad_key' - error = {"unauthorized": {"message": "Unauthorized", - "code": "401"}} - - self.stub_auth(status_code=401, json=error) - - with testcase.ExpectedException(exceptions.Unauthorized): - with self.deprecations.expect_deprecations_here(): - client.Client(username=self.TEST_USER, - password="bad_key", - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_redirect(self): - self.stub_auth(status_code=305, text='Use Proxy', - headers={'Location': self.TEST_ADMIN_URL + "/tokens"}) - - self.stub_auth(base_url=self.TEST_ADMIN_URL, - json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_password_unscoped(self): - del self.TEST_RESPONSE_DICT['access']['serviceCatalog'] - del self.TEST_REQUEST_BODY['auth']['tenantId'] - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertNotIn('serviceCatalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_url_token_authentication(self): - fake_token = 'fake_token' - fake_url = '/fake-url' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - with self.deprecations.expect_deprecations_here(): - cl = client.Client(auth_url=self.TEST_URL, - token=fake_token) - json_body = jsonutils.loads(self.requests_mock.last_request.body) - self.assertEqual(json_body['auth']['token']['id'], fake_token) - - with self.deprecations.expect_deprecations_here(): - resp, body = cl.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - def test_authenticate_success_token_scoped(self): - del self.TEST_REQUEST_BODY['auth']['passwordCredentials'] - self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_scoped_trust(self): - del self.TEST_REQUEST_BODY['auth']['passwordCredentials'] - self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} - self.TEST_REQUEST_BODY['auth']['trust_id'] = self.TEST_TRUST_ID - response = self.TEST_RESPONSE_DICT.copy() - response['access']['trust'] = {"trustee_user_id": self.TEST_USER, - "id": self.TEST_TRUST_ID} - self.stub_auth(json=response) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - trust_id=self.TEST_TRUST_ID, - auth_url=self.TEST_URL) - self.assertTrue(cs.auth_ref.trust_scoped) - self.assertEqual(cs.auth_ref.trust_id, self.TEST_TRUST_ID) - self.assertEqual(cs.auth_ref.trustee_user_id, self.TEST_USER) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_unscoped(self): - del self.TEST_REQUEST_BODY['auth']['passwordCredentials'] - del self.TEST_REQUEST_BODY['auth']['tenantId'] - del self.TEST_RESPONSE_DICT['access']['serviceCatalog'] - self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertNotIn('serviceCatalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_allow_override_of_auth_token(self): - fake_url = '/fake-url' - fake_token = 'fake_token' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - - self.assertEqual(cl.auth_token, self.TEST_TOKEN) - - # the token returned from the authentication will be used - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - # then override that token and the new token shall be used - cl.auth_token = fake_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(fake_token, token) - - # if we clear that overridden token then we fall back to the original - del cl.auth_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) diff --git a/keystoneclient/tests/unit/v2_0/test_certificates.py b/keystoneclient/tests/unit/v2_0/test_certificates.py deleted file mode 100644 index 4f689d9a..00000000 --- a/keystoneclient/tests/unit/v2_0/test_certificates.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 IBM Corp. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testresources - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils - - -class CertificateTests(utils.ClientTestCase, testresources.ResourcedTestCase): - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_get_ca_certificate(self): - self.stub_url('GET', ['certificates', 'ca'], - headers={'Content-Type': 'text/html; charset=UTF-8'}, - text=self.examples.SIGNING_CA) - res = self.client.certificates.get_ca_certificate() - self.assertEqual(self.examples.SIGNING_CA, res) - - def test_get_signing_certificate(self): - self.stub_url('GET', ['certificates', 'signing'], - headers={'Content-Type': 'text/html; charset=UTF-8'}, - text=self.examples.SIGNING_CERT) - res = self.client.certificates.get_signing_certificate() - self.assertEqual(self.examples.SIGNING_CERT, res) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v2_0/test_client.py b/keystoneclient/tests/unit/v2_0/test_client.py deleted file mode 100644 index cddac4d2..00000000 --- a/keystoneclient/tests/unit/v2_0/test_client.py +++ /dev/null @@ -1,220 +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. - -import json -import uuid - -from keystoneauth1 import fixture - -from keystoneauth1 import session as auth_session -from keystoneclient.auth import token_endpoint -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client - - -class KeystoneClientTest(utils.TestCase): - - def test_unscoped_init(self): - token = client_fixtures.unscoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username='exampleuser', - password='password', - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertFalse(c.auth_ref.scoped) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertIsNone(c.auth_ref.trust_id) - self.assertFalse(c.auth_ref.trust_scoped) - self.assertIsNone(c.get_project_id(session=None)) - self.assertEqual(token.user_id, c.get_user_id(session=None)) - - def test_scoped_init(self): - token = client_fixtures.project_scoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertTrue(c.auth_ref.scoped) - self.assertTrue(c.auth_ref.project_scoped) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertIsNone(c.auth_ref.trust_id) - self.assertFalse(c.auth_ref.trust_scoped) - - self.assertEqual(token.tenant_id, c.get_project_id(session=None)) - self.assertEqual(token.user_id, c.get_user_id(session=None)) - - def test_auth_ref_load(self): - self.stub_auth(json=client_fixtures.project_scoped_token()) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - cache = json.dumps(cl.auth_ref) - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache)) - self.assertIsNotNone(new_client.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertTrue(new_client.auth_ref.scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertIsNone(new_client.auth_ref.trust_id) - self.assertFalse(new_client.auth_ref.trust_scoped) - self.assertEqual(new_client.username, 'exampleuser') - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v2.0') - - def test_auth_ref_load_with_overridden_arguments(self): - self.stub_auth(json=client_fixtures.project_scoped_token()) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - cache = json.dumps(cl.auth_ref) - new_auth_url = "http://new-public:5000/v2.0" - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache), - auth_url=new_auth_url) - self.assertIsNotNone(new_client.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertTrue(new_client.auth_ref.scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertIsNone(new_client.auth_ref.trust_id) - self.assertFalse(new_client.auth_ref.trust_scoped) - self.assertEqual(new_client.auth_url, new_auth_url) - self.assertEqual(new_client.username, 'exampleuser') - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v2.0') - - def test_init_err_no_auth_url(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - username='exampleuser', - password='password') - - def test_management_url_is_updated(self): - first = fixture.V2Token() - first.set_scope() - admin_url = 'http://admin:35357/v2.0' - second_url = 'http://secondurl:35357/v2.0' - - s = first.add_service('identity') - s.add_endpoint(public='http://public.com:5000/v2.0', - admin=admin_url) - - second = fixture.V2Token() - second.set_scope() - s = second.add_service('identity') - s.add_endpoint(public='http://secondurl:5000/v2.0', - admin=second_url) - - self.stub_auth(response_list=[{'json': first}, {'json': second}]) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - self.assertEqual(cl.management_url, admin_url) - - with self.deprecations.expect_deprecations_here(): - cl.authenticate() - self.assertEqual(cl.management_url, second_url) - - def test_client_with_region_name_passes_to_service_catalog(self): - # NOTE(jamielennox): this is deprecated behaviour that should be - # removed ASAP, however must remain compatible. - self.stub_auth(json=client_fixtures.auth_response_body()) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='North') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'https://image.north.host/v1/') - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='South') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'https://image.south.host/v1/') - - def test_client_without_auth_params(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - project_name='exampleproject', - auth_url=self.TEST_URL) - - def test_client_params(self): - with self.deprecations.expect_deprecations_here(): - sess = session.Session() - auth = token_endpoint.Token('a', 'b') - - opts = {'auth': auth, - 'connect_retries': 50, - 'endpoint_override': uuid.uuid4().hex, - 'interface': uuid.uuid4().hex, - 'region_name': uuid.uuid4().hex, - 'service_name': uuid.uuid4().hex, - 'user_agent': uuid.uuid4().hex, - } - - cl = client.Client(session=sess, **opts) - - for k, v in opts.items(): - self.assertEqual(v, getattr(cl._adapter, k)) - - self.assertEqual('identity', cl._adapter.service_type) - self.assertEqual((2, 0), cl._adapter.version) - - def test_empty_service_catalog_param(self): - # Client().service_catalog should return None if the client is not - # authenticated - sess = auth_session.Session() - cl = client.Client(session=sess) - self.assertIsNone(cl.service_catalog) diff --git a/keystoneclient/tests/unit/v2_0/test_discovery.py b/keystoneclient/tests/unit/v2_0/test_discovery.py deleted file mode 100644 index a3700e0e..00000000 --- a/keystoneclient/tests/unit/v2_0/test_discovery.py +++ /dev/null @@ -1,84 +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.generic import client -from keystoneclient.tests.unit.v2_0 import utils - - -class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): - def setUp(self): - super(DiscoverKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "versions": { - "values": [{ - "id": "v2.0", - "status": "beta", - "updated": "2011-11-19T00:00:00Z", - "links": [ - {"rel": "self", - "href": "http://127.0.0.1:5000/v2.0/", }, - {"rel": "describedby", - "type": "text/html", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/content/", }, - {"rel": "describedby", - "type": "application/pdf", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/" - "identity-dev-guide-2.0.pdf", }, - {"rel": "describedby", - "type": "application/vnd.sun.wadl+xml", - "href": "http://127.0.0.1:5000/v2.0/identity.wadl", } - ], - "media-types": [{ - "base": "application/xml", - "type": "application/vnd.openstack.identity-v2.0+xml", - }, { - "base": "application/json", - "type": "application/vnd.openstack.identity-v2.0+json", - }], - }], - }, - } - - def test_get_versions(self): - self.stub_url('GET', base_url=self.TEST_ROOT_URL, - json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client() - versions = cs.discover(self.TEST_ROOT_URL) - self.assertIsInstance(versions, dict) - self.assertIn('message', versions) - self.assertIn('v2.0', versions) - self.assertEqual( - versions['v2.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][0]['links'][0] - ['href']) - - def test_get_version_local(self): - self.stub_url('GET', base_url="http://localhost:35357/", - json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client() - versions = cs.discover() - self.assertIsInstance(versions, dict) - self.assertIn('message', versions) - self.assertIn('v2.0', versions) - self.assertEqual( - versions['v2.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][0]['links'][0] - ['href']) diff --git a/keystoneclient/tests/unit/v2_0/test_ec2.py b/keystoneclient/tests/unit/v2_0/test_ec2.py deleted file mode 100644 index 3df053de..00000000 --- a/keystoneclient/tests/unit/v2_0/test_ec2.py +++ /dev/null @@ -1,107 +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.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import ec2 - - -class EC2Tests(utils.ClientTestCase): - - def test_create(self): - user_id = 'usr' - tenant_id = 'tnt' - req_body = { - "tenant_id": tenant_id, - } - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('POST', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - cred = self.client.ec2.create(user_id, tenant_id) - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - self.assertRequestBodyIs(json=req_body) - - def test_get(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2', 'access'], json=resp_body) - - cred = self.client.ec2.get(user_id, 'access') - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_list(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credentials": { - "values": [ - { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - }, - { - "access": "another", - "secret": "key", - "tenant_id": tenant_id, - "created": "12/12/31", - "enabled": True, - } - ] - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - creds = self.client.ec2.list(user_id) - self.assertEqual(len(creds), 2) - cred = creds[0] - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_delete(self): - user_id = 'usr' - access = 'access' - self.stub_url('DELETE', ['users', user_id, 'credentials', - 'OS-EC2', access], status_code=204) - self.client.ec2.delete(user_id, access) diff --git a/keystoneclient/tests/unit/v2_0/test_endpoints.py b/keystoneclient/tests/unit/v2_0/test_endpoints.py deleted file mode 100644 index 7b15cccc..00000000 --- a/keystoneclient/tests/unit/v2_0/test_endpoints.py +++ /dev/null @@ -1,147 +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. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import endpoints - - -class EndpointTests(utils.ClientTestCase): - def setUp(self): - super(EndpointTests, self).setUp() - self.TEST_ENDPOINTS = { - 'endpoints': [ - { - 'adminurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'id': '8f9531231e044e218824b0e58688d262', - 'internalurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'publicurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'region': 'RegionOne', - }, - { - 'adminurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'id': '8f9531231e044e218824b0e58688d263', - 'internalurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'publicurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'region': 'RegionOne', - } - ] - } - - def test_create_with_optional_params(self): - req_body = { - "endpoint": { - "region": "RegionOne", - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "internalurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "service_id": uuid.uuid4().hex, - } - } - - resp_body = { - "endpoint": { - "adminurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "region": "RegionOne", - "id": uuid.uuid4().hex, - "internalurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - } - } - - self.stub_url('POST', ['endpoints'], json=resp_body) - - endpoint = self.client.endpoints.create( - region=req_body['endpoint']['region'], - publicurl=req_body['endpoint']['publicurl'], - adminurl=req_body['endpoint']['adminurl'], - internalurl=req_body['endpoint']['internalurl'], - service_id=req_body['endpoint']['service_id'] - ) - self.assertIsInstance(endpoint, endpoints.Endpoint) - self.assertRequestBodyIs(json=req_body) - - def test_create_with_optional_params_as_none(self): - req_body_without_defaults = { - "endpoint": { - "region": "RegionOne", - "service_id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - resp_body = { - "endpoint": { - "region": "RegionOne", - "id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - self.stub_url('POST', ['endpoints'], json=resp_body) - - endpoint_without_defaults = self.client.endpoints.create( - region=req_body_without_defaults['endpoint']['region'], - publicurl=req_body_without_defaults['endpoint']['publicurl'], - service_id=req_body_without_defaults['endpoint']['service_id'], - adminurl=None, - internalurl=None - ) - self.assertIsInstance(endpoint_without_defaults, endpoints.Endpoint) - self.assertRequestBodyIs(json=req_body_without_defaults) - - def test_create_without_optional_params(self): - req_body_without_defaults = { - "endpoint": { - "region": "RegionOne", - "service_id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - resp_body = { - "endpoint": { - "region": "RegionOne", - "id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - self.stub_url('POST', ['endpoints'], json=resp_body) - - endpoint_without_defaults = self.client.endpoints.create( - region=req_body_without_defaults['endpoint']['region'], - publicurl=req_body_without_defaults['endpoint']['publicurl'], - service_id=req_body_without_defaults['endpoint']['service_id'] - ) - self.assertIsInstance(endpoint_without_defaults, endpoints.Endpoint) - self.assertRequestBodyIs(json=req_body_without_defaults) - - def test_delete(self): - self.stub_url('DELETE', ['endpoints', '8f953'], status_code=204) - self.client.endpoints.delete('8f953') - - def test_list(self): - self.stub_url('GET', ['endpoints'], json=self.TEST_ENDPOINTS) - - endpoint_list = self.client.endpoints.list() - [self.assertIsInstance(r, endpoints.Endpoint) - for r in endpoint_list] diff --git a/keystoneclient/tests/unit/v2_0/test_extensions.py b/keystoneclient/tests/unit/v2_0/test_extensions.py deleted file mode 100644 index 3927bc07..00000000 --- a/keystoneclient/tests/unit/v2_0/test_extensions.py +++ /dev/null @@ -1,63 +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.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import extensions - - -class ExtensionTests(utils.ClientTestCase): - def setUp(self): - super(ExtensionTests, self).setUp() - self.TEST_EXTENSIONS = { - 'extensions': { - "values": [ - { - 'name': 'OpenStack Keystone User CRUD', - 'namespace': 'https://docs.openstack.org/' - 'identity/api/ext/OS-KSCRUD/v1.0', - 'updated': '2013-07-07T12:00:0-00:00', - 'alias': 'OS-KSCRUD', - 'description': - 'OpenStack extensions to Keystone v2.0 API' - ' enabling User Operations.', - 'links': - '[{"href":' - '"https://github.com/openstack/identity-api", "type":' - ' "text/html", "rel": "describedby"}]', - }, - { - 'name': 'OpenStack EC2 API', - 'namespace': 'https://docs.openstack.org/' - 'identity/api/ext/OS-EC2/v1.0', - 'updated': '2013-09-07T12:00:0-00:00', - 'alias': 'OS-EC2', - 'description': 'OpenStack EC2 Credentials backend.', - 'links': '[{"href":' - '"https://github.com/openstack/identity-api", "type":' - ' "text/html", "rel": "describedby"}]', - } - ] - } - } - - def test_list(self): - self.stub_url('GET', ['extensions'], json=self.TEST_EXTENSIONS) - extensions_list = self.client.extensions.list() - self.assertEqual(2, len(extensions_list)) - for extension in extensions_list: - self.assertIsInstance(extension, extensions.Extension) - self.assertIsNotNone(extension.alias) - self.assertIsNotNone(extension.description) - self.assertIsNotNone(extension.links) - self.assertIsNotNone(extension.name) - self.assertIsNotNone(extension.namespace) - self.assertIsNotNone(extension.updated) diff --git a/keystoneclient/tests/unit/v2_0/test_roles.py b/keystoneclient/tests/unit/v2_0/test_roles.py deleted file mode 100644 index fab21383..00000000 --- a/keystoneclient/tests/unit/v2_0/test_roles.py +++ /dev/null @@ -1,121 +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. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import roles - - -class RoleTests(utils.ClientTestCase): - def setUp(self): - super(RoleTests, self).setUp() - - self.ADMIN_ROLE_ID = uuid.uuid4().hex - self.MEMBER_ROLE_ID = uuid.uuid4().hex - - self.TEST_ROLES = { - "roles": { - "values": [ - { - "name": "admin", - "id": self.ADMIN_ROLE_ID, - }, - { - "name": "member", - "id": self.MEMBER_ROLE_ID, - } - ], - }, - } - - def test_create(self): - req_body = { - "role": { - "name": "sysadmin", - } - } - role_id = uuid.uuid4().hex - resp_body = { - "role": { - "name": "sysadmin", - "id": role_id, - } - } - self.stub_url('POST', ['OS-KSADM', 'roles'], json=resp_body) - - role = self.client.roles.create(req_body['role']['name']) - self.assertRequestBodyIs(json=req_body) - self.assertIsInstance(role, roles.Role) - self.assertEqual(role.id, role_id) - self.assertEqual(role.name, req_body['role']['name']) - - def test_delete(self): - self.stub_url('DELETE', - ['OS-KSADM', 'roles', self.ADMIN_ROLE_ID], - status_code=204) - self.client.roles.delete(self.ADMIN_ROLE_ID) - - def test_get(self): - self.stub_url('GET', ['OS-KSADM', 'roles', self.ADMIN_ROLE_ID], - json={'role': self.TEST_ROLES['roles']['values'][0]}) - - role = self.client.roles.get(self.ADMIN_ROLE_ID) - self.assertIsInstance(role, roles.Role) - self.assertEqual(role.id, self.ADMIN_ROLE_ID) - self.assertEqual(role.name, 'admin') - - def test_list(self): - self.stub_url('GET', ['OS-KSADM', 'roles'], - json=self.TEST_ROLES) - - role_list = self.client.roles.list() - [self.assertIsInstance(r, roles.Role) for r in role_list] - - def test_roles_for_user(self): - self.stub_url('GET', ['users', 'foo', 'roles'], - json=self.TEST_ROLES) - - role_list = self.client.roles.roles_for_user('foo') - [self.assertIsInstance(r, roles.Role) for r in role_list] - - def test_roles_for_user_tenant(self): - self.stub_url('GET', ['tenants', 'barrr', 'users', 'foo', - 'roles'], json=self.TEST_ROLES) - - role_list = self.client.roles.roles_for_user('foo', 'barrr') - [self.assertIsInstance(r, roles.Role) for r in role_list] - - def test_add_user_role(self): - self.stub_url('PUT', ['users', 'foo', 'roles', 'OS-KSADM', - 'barrr'], status_code=204) - - self.client.roles.add_user_role('foo', 'barrr') - - def test_add_user_role_tenant(self): - id_ = uuid.uuid4().hex - self.stub_url('PUT', ['tenants', id_, 'users', 'foo', 'roles', - 'OS-KSADM', 'barrr'], status_code=204) - - self.client.roles.add_user_role('foo', 'barrr', id_) - - def test_remove_user_role(self): - self.stub_url('DELETE', ['users', 'foo', 'roles', 'OS-KSADM', - 'barrr'], status_code=204) - self.client.roles.remove_user_role('foo', 'barrr') - - def test_remove_user_role_tenant(self): - id_ = uuid.uuid4().hex - self.stub_url('DELETE', ['tenants', id_, 'users', 'foo', - 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - self.client.roles.remove_user_role('foo', 'barrr', id_) diff --git a/keystoneclient/tests/unit/v2_0/test_service_catalog.py b/keystoneclient/tests/unit/v2_0/test_service_catalog.py deleted file mode 100644 index 612b7f0a..00000000 --- a/keystoneclient/tests/unit/v2_0/test_service_catalog.py +++ /dev/null @@ -1,207 +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 keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient import exceptions -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils - - -class ServiceCatalogTest(utils.TestCase): - def setUp(self): - super(ServiceCatalogTest, self).setUp() - self.AUTH_RESPONSE_BODY = client_fixtures.auth_response_body() - - def test_building_a_service_catalog(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - self.assertEqual(sc.url_for(service_type='compute'), - "https://compute.north.host/v1/1234") - self.assertEqual(sc.url_for('tenantId', '1', service_type='compute'), - "https://compute.north.host/v1/1234") - self.assertEqual(sc.url_for('tenantId', '2', service_type='compute'), - "https://compute.north.host/v1.1/3456") - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, "region", - "South", service_type='compute') - - def test_service_catalog_endpoints(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - public_ep = sc.get_endpoints(service_type='compute', - endpoint_type='publicURL') - self.assertEqual(public_ep['compute'][1]['tenantId'], '2') - self.assertEqual(public_ep['compute'][1]['versionId'], '1.1') - self.assertEqual(public_ep['compute'][1]['internalURL'], - "https://compute.north.host/v1.1/3456") - - def test_service_catalog_regions(self): - self.AUTH_RESPONSE_BODY['access']['region_name'] = "North" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', endpoint_type='publicURL') - self.assertEqual(url, "https://image.north.host/v1/") - - self.AUTH_RESPONSE_BODY['access']['region_name'] = "South" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', endpoint_type='internalURL') - self.assertEqual(url, "https://image-internal.south.host/v1/") - - def test_service_catalog_empty(self): - self.AUTH_RESPONSE_BODY['access']['serviceCatalog'] = [] - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - self.assertRaises(exceptions.EmptyCatalog, - auth_ref.service_catalog.url_for, - service_type='image', - endpoint_type='internalURL') - - def test_service_catalog_get_endpoints_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - endpoints = sc.get_endpoints(service_type='image', region_name='North') - self.assertEqual(len(endpoints), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.north.host/v1/') - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.south.host/v1/') - - endpoints = sc.get_endpoints(service_type='compute') - self.assertEqual(len(endpoints['compute']), 2) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='North') - self.assertEqual(len(endpoints['compute']), 2) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='West') - self.assertEqual(len(endpoints['compute']), 0) - - def test_service_catalog_url_for_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', region_name='North') - self.assertEqual(url, 'https://image.north.host/v1/') - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, 'https://image.south.host/v1/') - - url = sc.url_for(service_type='compute', - region_name='North', - attr='versionId', - filter_value='1.1') - self.assertEqual(url, 'https://compute.north.host/v1.1/3456') - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_type='image', region_name='West') - - def test_servcie_catalog_get_url_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - urls = sc.get_urls(service_type='image') - self.assertEqual(len(urls), 2) - - urls = sc.get_urls(service_type='image', region_name='North') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], 'https://image.north.host/v1/') - - urls = sc.get_urls(service_type='image', region_name='South') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], 'https://image.south.host/v1/') - - urls = sc.get_urls(service_type='image', region_name='West') - self.assertIsNone(urls) - - def test_service_catalog_param_overrides_body_region(self): - self.AUTH_RESPONSE_BODY['access']['region_name'] = "North" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image') - self.assertEqual(url, 'https://image.north.host/v1/') - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, 'https://image.south.host/v1/') - - endpoints = sc.get_endpoints(service_type='image') - self.assertEqual(len(endpoints['image']), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.north.host/v1/') - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints['image']), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.south.host/v1/') - - def test_service_catalog_service_name(self): - auth_ref = access.AccessInfo.factory(resp=None, - body=self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_name='Image Servers', endpoint_type='public', - service_type='image', region_name='North') - self.assertEqual('https://image.north.host/v1/', url) - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_name='Image Servers', service_type='compute') - - urls = sc.get_urls(service_type='image', service_name='Image Servers', - endpoint_type='public') - - self.assertIn('https://image.north.host/v1/', urls) - self.assertIn('https://image.south.host/v1/', urls) - - urls = sc.get_urls(service_type='image', service_name='Servers', - endpoint_type='public') - - self.assertIsNone(urls) - - def test_service_catalog_multiple_service_types(self): - token = fixture.V2Token() - token.set_scope() - - for i in range(3): - s = token.add_service('compute') - s.add_endpoint(public='public-%d' % i, - admin='admin-%d' % i, - internal='internal-%d' % i, - region='region-%d' % i) - - auth_ref = access.AccessInfo.factory(resp=None, body=token) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='publicURL') - - self.assertEqual(set(['public-0', 'public-1', 'public-2']), set(urls)) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='publicURL', - region_name='region-1') - - self.assertEqual(('public-1', ), urls) diff --git a/keystoneclient/tests/unit/v2_0/test_services.py b/keystoneclient/tests/unit/v2_0/test_services.py deleted file mode 100644 index 72c54769..00000000 --- a/keystoneclient/tests/unit/v2_0/test_services.py +++ /dev/null @@ -1,129 +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. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import services - - -class ServiceTests(utils.ClientTestCase): - def setUp(self): - super(ServiceTests, self).setUp() - - self.NOVA_SERVICE_ID = uuid.uuid4().hex - self.KEYSTONE_SERVICE_ID = uuid.uuid4().hex - - self.TEST_SERVICES = { - "OS-KSADM:services": { - "values": [ - { - "name": "nova", - "type": "compute", - "description": "Nova-compatible service.", - "id": self.NOVA_SERVICE_ID - }, - { - "name": "keystone", - "type": "identity", - "description": "Keystone-compatible service.", - "id": self.KEYSTONE_SERVICE_ID - }, - ], - }, - } - - def test_create_with_description(self): - req_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "description": "Swift-compatible service.", - } - } - service_id = uuid.uuid4().hex - resp_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "description": "Swift-compatible service.", - "id": service_id, - } - } - self.stub_url('POST', ['OS-KSADM', 'services'], json=resp_body) - - service = self.client.services.create( - req_body['OS-KSADM:service']['name'], - req_body['OS-KSADM:service']['type'], - req_body['OS-KSADM:service']['description']) - self.assertIsInstance(service, services.Service) - self.assertEqual(service.id, service_id) - self.assertEqual(service.name, req_body['OS-KSADM:service']['name']) - self.assertEqual(service.description, - req_body['OS-KSADM:service']['description']) - self.assertRequestBodyIs(json=req_body) - - def test_create_without_description(self): - req_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "description": None, - } - } - service_id = uuid.uuid4().hex - resp_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "id": service_id, - "description": None, - } - } - self.stub_url('POST', ['OS-KSADM', 'services'], json=resp_body) - - service = self.client.services.create( - req_body['OS-KSADM:service']['name'], - req_body['OS-KSADM:service']['type'], - req_body['OS-KSADM:service']['description']) - self.assertIsInstance(service, services.Service) - self.assertEqual(service.id, service_id) - self.assertEqual(service.name, req_body['OS-KSADM:service']['name']) - self.assertIsNone(service.description) - self.assertRequestBodyIs(json=req_body) - - def test_delete(self): - self.stub_url('DELETE', - ['OS-KSADM', 'services', self.NOVA_SERVICE_ID], - status_code=204) - - self.client.services.delete(self.NOVA_SERVICE_ID) - - def test_get(self): - test_services = self.TEST_SERVICES['OS-KSADM:services']['values'][0] - - self.stub_url('GET', ['OS-KSADM', 'services', self.NOVA_SERVICE_ID], - json={'OS-KSADM:service': test_services}) - - service = self.client.services.get(self.NOVA_SERVICE_ID) - self.assertIsInstance(service, services.Service) - self.assertEqual(service.id, self.NOVA_SERVICE_ID) - self.assertEqual(service.name, 'nova') - self.assertEqual(service.type, 'compute') - - def test_list(self): - self.stub_url('GET', ['OS-KSADM', 'services'], - json=self.TEST_SERVICES) - - service_list = self.client.services.list() - [self.assertIsInstance(r, services.Service) - for r in service_list] diff --git a/keystoneclient/tests/unit/v2_0/test_tenants.py b/keystoneclient/tests/unit/v2_0/test_tenants.py deleted file mode 100644 index 5e78aa3b..00000000 --- a/keystoneclient/tests/unit/v2_0/test_tenants.py +++ /dev/null @@ -1,366 +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. - -import uuid - -from keystoneauth1 import exceptions -from keystoneauth1 import fixture - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client -from keystoneclient.v2_0 import tenants -from keystoneclient.v2_0 import users - - -class TenantTests(utils.ClientTestCase): - def setUp(self): - super(TenantTests, self).setUp() - - self.INVIS_ID = uuid.uuid4().hex - self.DEMO_ID = uuid.uuid4().hex - self.ADMIN_ID = uuid.uuid4().hex - self.EXTRAS_ID = uuid.uuid4().hex - - self.TEST_TENANTS = { - "tenants": { - "values": [ - { - "enabled": True, - "description": "A description change!", - "name": "invisible_to_admin", - "id": self.INVIS_ID, - }, - { - "enabled": True, - "description": "None", - "name": "demo", - "id": self.DEMO_ID, - }, - { - "enabled": True, - "description": "None", - "name": "admin", - "id": self.ADMIN_ID, - }, - { - "extravalue01": "metadata01", - "enabled": True, - "description": "For testing extras", - "name": "test_extras", - "id": self.EXTRAS_ID, - } - ], - "links": [], - }, - } - - def test_create(self): - req_body = { - "tenant": { - "name": "tenantX", - "description": "Like tenant 9, but better.", - "enabled": True, - "extravalue01": "metadata01", - }, - } - id_ = uuid.uuid4().hex - resp_body = { - "tenant": { - "name": "tenantX", - "enabled": True, - "id": id_, - "description": "Like tenant 9, but better.", - "extravalue01": "metadata01", - } - } - self.stub_url('POST', ['tenants'], json=resp_body) - - tenant = self.client.tenants.create( - req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled'], - extravalue01=req_body['tenant']['extravalue01'], - name="don't overwrite priors") - self.assertIsInstance(tenant, tenants.Tenant) - self.assertEqual(tenant.id, id_) - self.assertEqual(tenant.name, "tenantX") - self.assertEqual(tenant.description, "Like tenant 9, but better.") - self.assertEqual(tenant.extravalue01, "metadata01") - self.assertRequestBodyIs(json=req_body) - - def test_duplicate_create(self): - req_body = { - "tenant": { - "name": "tenantX", - "description": "The duplicate tenant.", - "enabled": True - }, - } - resp_body = { - "error": { - "message": "Conflict occurred attempting to store project.", - "code": 409, - "title": "Conflict", - } - } - self.stub_url('POST', ['tenants'], status_code=409, json=resp_body) - - def create_duplicate_tenant(): - self.client.tenants.create(req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled']) - - self.assertRaises(exceptions.Conflict, create_duplicate_tenant) - - def test_delete(self): - self.stub_url('DELETE', ['tenants', self.ADMIN_ID], status_code=204) - self.client.tenants.delete(self.ADMIN_ID) - - def test_get(self): - resp = {'tenant': self.TEST_TENANTS['tenants']['values'][2]} - self.stub_url('GET', ['tenants', self.ADMIN_ID], json=resp) - - t = self.client.tenants.get(self.ADMIN_ID) - self.assertIsInstance(t, tenants.Tenant) - self.assertEqual(t.id, self.ADMIN_ID) - self.assertEqual(t.name, 'admin') - - def test_list(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list() - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_list_limit(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list(limit=1) - self.assertQueryStringIs('limit=1') - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_list_marker(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list(marker=1) - self.assertQueryStringIs('marker=1') - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_list_limit_marker(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list(limit=1, marker=1) - self.assertQueryStringIs('marker=1&limit=1') - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_update(self): - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "I changed you!", - "enabled": False, - "extravalue01": "metadataChanged", - # "extraname": "dontoverwrite!", - }, - } - resp_body = { - "tenant": { - "name": "tenantX", - "enabled": False, - "id": self.EXTRAS_ID, - "description": "I changed you!", - "extravalue01": "metadataChanged", - }, - } - - self.stub_url('POST', ['tenants', self.EXTRAS_ID], json=resp_body) - - tenant = self.client.tenants.update( - req_body['tenant']['id'], - req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled'], - extravalue01=req_body['tenant']['extravalue01'], - name="don't overwrite priors") - self.assertIsInstance(tenant, tenants.Tenant) - self.assertRequestBodyIs(json=req_body) - self.assertEqual(tenant.id, self.EXTRAS_ID) - self.assertEqual(tenant.name, "tenantX") - self.assertEqual(tenant.description, "I changed you!") - self.assertFalse(tenant.enabled) - self.assertEqual(tenant.extravalue01, "metadataChanged") - - def test_update_empty_description(self): - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "", - "enabled": False, - }, - } - resp_body = { - "tenant": { - "name": "tenantX", - "enabled": False, - "id": self.EXTRAS_ID, - "description": "", - }, - } - self.stub_url('POST', ['tenants', self.EXTRAS_ID], json=resp_body) - - tenant = self.client.tenants.update(req_body['tenant']['id'], - req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled']) - self.assertIsInstance(tenant, tenants.Tenant) - self.assertRequestBodyIs(json=req_body) - self.assertEqual(tenant.id, self.EXTRAS_ID) - self.assertEqual(tenant.name, "tenantX") - self.assertEqual(tenant.description, "") - self.assertFalse(tenant.enabled) - - def test_add_user(self): - self.stub_url('PUT', - ['tenants', self.EXTRAS_ID, 'users', 'foo', 'roles', - 'OS-KSADM', 'barrr'], - status_code=204) - - self.client.tenants.add_user(self.EXTRAS_ID, 'foo', 'barrr') - - def test_remove_user(self): - self.stub_url('DELETE', ['tenants', self.EXTRAS_ID, 'users', - 'foo', 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - - self.client.tenants.remove_user(self.EXTRAS_ID, 'foo', 'barrr') - - def test_tenant_add_user(self): - self.stub_url('PUT', ['tenants', self.EXTRAS_ID, 'users', - 'foo', 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "I changed you!", - "enabled": False, - }, - } - # make tenant object with manager - tenant = self.client.tenants.resource_class(self.client.tenants, - req_body['tenant']) - tenant.add_user('foo', 'barrr') - self.assertIsInstance(tenant, tenants.Tenant) - - def test_tenant_remove_user(self): - self.stub_url('DELETE', ['tenants', self.EXTRAS_ID, 'users', - 'foo', 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "I changed you!", - "enabled": False, - }, - } - - # make tenant object with manager - tenant = self.client.tenants.resource_class(self.client.tenants, - req_body['tenant']) - tenant.remove_user('foo', 'barrr') - self.assertIsInstance(tenant, tenants.Tenant) - - def test_tenant_list_users(self): - tenant_id = uuid.uuid4().hex - user_id1 = uuid.uuid4().hex - user_id2 = uuid.uuid4().hex - - tenant_resp = { - 'tenant': { - 'name': uuid.uuid4().hex, - 'enabled': True, - 'id': tenant_id, - 'description': 'test tenant', - } - } - - users_resp = { - 'users': { - 'values': [ - { - 'email': uuid.uuid4().hex, - 'enabled': True, - 'id': user_id1, - 'name': uuid.uuid4().hex, - }, - { - 'email': uuid.uuid4().hex, - 'enabled': True, - 'id': user_id2, - 'name': uuid.uuid4().hex, - }, - ] - } - } - - self.stub_url('GET', ['tenants', tenant_id], json=tenant_resp) - self.stub_url('GET', - ['tenants', tenant_id, 'users'], - json=users_resp) - - tenant = self.client.tenants.get(tenant_id) - user_objs = tenant.list_users() - - for u in user_objs: - self.assertIsInstance(u, users.User) - - self.assertEqual(set([user_id1, user_id2]), - set([u.id for u in user_objs])) - - def test_list_tenants_use_admin_url(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list() - self.assertEqual(self.TEST_URL + '/tenants', - self.requests_mock.last_request.url) - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - self.assertEqual(len(self.TEST_TENANTS['tenants']['values']), - len(tenant_list)) - - def test_list_tenants_fallback_to_auth_url(self): - new_auth_url = 'http://keystone.test:5000/v2.0' - - token = fixture.V2Token(token_id=self.TEST_TOKEN, - user_name=self.TEST_USER, - user_id=self.TEST_USER_ID) - - self.stub_auth(base_url=new_auth_url, json=token) - self.stub_url('GET', ['tenants'], base_url=new_auth_url, - json=self.TEST_TENANTS) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username=self.TEST_USER, - auth_url=new_auth_url, - password=uuid.uuid4().hex) - - self.assertIsNone(c.management_url) - tenant_list = c.tenants.list() - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - self.assertEqual(len(self.TEST_TENANTS['tenants']['values']), - len(tenant_list)) diff --git a/keystoneclient/tests/unit/v2_0/test_tokens.py b/keystoneclient/tests/unit/v2_0/test_tokens.py deleted file mode 100644 index 58df7c21..00000000 --- a/keystoneclient/tests/unit/v2_0/test_tokens.py +++ /dev/null @@ -1,217 +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. - -import uuid - -from keystoneauth1 import exceptions -from keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client -from keystoneclient.v2_0 import tokens - - -class TokenTests(utils.ClientTestCase): - - def test_delete(self): - id_ = uuid.uuid4().hex - self.stub_url('DELETE', ['tokens', id_], status_code=204) - self.client.tokens.delete(id_) - - def test_user_password(self): - token_fixture = fixture.V2Token(user_name=self.TEST_USER) - self.stub_auth(json=token_fixture) - - password = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(username=self.TEST_USER, - password=password) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - req_body = { - 'auth': { - 'passwordCredentials': { - 'username': self.TEST_USER, - 'password': password, - } - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_with_token_id(self): - token_fixture = fixture.V2Token() - self.stub_auth(json=token_fixture) - - token_id = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(token=token_id) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - req_body = { - 'auth': { - 'token': { - 'id': token_id, - } - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_without_auth_params(self): - self.assertRaises(ValueError, self.client.tokens.authenticate) - self.assertRaises(ValueError, self.client.tokens.authenticate, - tenant_id=uuid.uuid4().hex) - - def test_with_tenant_id(self): - token_fixture = fixture.V2Token() - token_fixture.set_scope() - self.stub_auth(json=token_fixture) - - token_id = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(token=token_id, - tenant_id=tenant_id) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - tenant_data = {'id': token_fixture.tenant_id, - 'name': token_fixture.tenant_name} - self.assertEqual(tenant_data, token_ref.tenant) - - req_body = { - 'auth': { - 'token': { - 'id': token_id, - }, - 'tenantId': tenant_id - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_with_tenant_name(self): - token_fixture = fixture.V2Token() - token_fixture.set_scope() - self.stub_auth(json=token_fixture) - - token_id = uuid.uuid4().hex - tenant_name = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(token=token_id, - tenant_name=tenant_name) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - tenant_data = {'id': token_fixture.tenant_id, - 'name': token_fixture.tenant_name} - self.assertEqual(tenant_data, token_ref.tenant) - - req_body = { - 'auth': { - 'token': { - 'id': token_id, - }, - 'tenantName': tenant_name - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_authenticate_use_admin_url(self): - token_fixture = fixture.V2Token() - token_fixture.set_scope() - self.stub_auth(json=token_fixture) - - token_ref = self.client.tokens.authenticate(token=uuid.uuid4().hex) - self.assertEqual(self.TEST_URL + '/tokens', - self.requests_mock.last_request.url) - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - def test_authenticate_fallback_to_auth_url(self): - new_auth_url = 'http://keystone.test:5000/v2.0' - - token_fixture = fixture.V2Token() - self.stub_auth(base_url=new_auth_url, json=token_fixture) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username=self.TEST_USER, - auth_url=new_auth_url, - password=uuid.uuid4().hex) - - self.assertIsNone(c.management_url) - - token_ref = c.tokens.authenticate(token=uuid.uuid4().hex) - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - def test_validate_token(self): - id_ = uuid.uuid4().hex - token_fixture = fixture.V2Token(token_id=id_) - self.stub_url('GET', ['tokens', id_], json=token_fixture) - - token_data = self.client.tokens.get_token_data(id_) - self.assertEqual(token_fixture, token_data) - - token_ref = self.client.tokens.validate(id_) - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(id_, token_ref.id) - - def test_validate_token_invalid_token(self): - # If the token is invalid, typically a NotFound is raised. - - id_ = uuid.uuid4().hex - # The server is expected to return 404 if the token is invalid. - self.stub_url('GET', ['tokens', id_], status_code=404) - - self.assertRaises(exceptions.NotFound, - self.client.tokens.get_token_data, id_) - self.assertRaises(exceptions.NotFound, - self.client.tokens.validate, id_) - - def test_validate_token_access_info_with_token_id(self): - # Can validate a token passing a string token ID. - token_id = uuid.uuid4().hex - token_fixture = fixture.V2Token(token_id=token_id) - self.stub_url('GET', ['tokens', token_id], json=token_fixture) - access_info = self.client.tokens.validate_access_info(token_id) - self.assertIsInstance(access_info, access.AccessInfoV2) - self.assertEqual(token_id, access_info.auth_token) - - def test_validate_token_access_info_with_access_info(self): - # Can validate a token passing an access info. - token_id = uuid.uuid4().hex - token_fixture = fixture.V2Token(token_id=token_id) - self.stub_url('GET', ['tokens', token_id], json=token_fixture) - token = access.AccessInfo.factory(body=token_fixture) - access_info = self.client.tokens.validate_access_info(token) - self.assertIsInstance(access_info, access.AccessInfoV2) - self.assertEqual(token_id, access_info.auth_token) - - def test_get_revoked(self): - sample_revoked_response = {'signed': '-----BEGIN CMS-----\nMIIB...'} - self.stub_url('GET', ['tokens', 'revoked'], - json=sample_revoked_response) - resp = self.client.tokens.get_revoked() - self.assertEqual(sample_revoked_response, resp) diff --git a/keystoneclient/tests/unit/v2_0/test_users.py b/keystoneclient/tests/unit/v2_0/test_users.py deleted file mode 100644 index d6507388..00000000 --- a/keystoneclient/tests/unit/v2_0/test_users.py +++ /dev/null @@ -1,301 +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. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import roles -from keystoneclient.v2_0 import users - - -class UserTests(utils.ClientTestCase): - def setUp(self): - super(UserTests, self).setUp() - self.ADMIN_USER_ID = uuid.uuid4().hex - self.DEMO_USER_ID = uuid.uuid4().hex - self.TEST_USERS = { - "users": { - "values": [ - { - "email": "None", - "enabled": True, - "id": self.ADMIN_USER_ID, - "name": "admin", - }, - { - "email": "None", - "enabled": True, - "id": self.DEMO_USER_ID, - "name": "demo", - }, - ] - } - } - - def test_create(self): - tenant_id = uuid.uuid4().hex - user_id = uuid.uuid4().hex - password = uuid.uuid4().hex - req_body = { - "user": { - "name": "gabriel", - "password": password, - "tenantId": tenant_id, - "email": "test@example.com", - "enabled": True, - } - } - - resp_body = { - "user": { - "name": "gabriel", - "enabled": True, - "tenantId": tenant_id, - "id": user_id, - "password": password, - "email": "test@example.com", - } - } - - self.stub_url('POST', ['users'], json=resp_body) - - user = self.client.users.create(req_body['user']['name'], - req_body['user']['password'], - req_body['user']['email'], - tenant_id=req_body['user']['tenantId'], - enabled=req_body['user']['enabled']) - self.assertIsInstance(user, users.User) - self.assertEqual(user.id, user_id) - self.assertEqual(user.name, "gabriel") - self.assertEqual(user.email, "test@example.com") - self.assertRequestBodyIs(json=req_body) - self.assertNotIn(password, self.logger.output) - - def test_create_user_without_email(self): - tenant_id = uuid.uuid4().hex - req_body = { - "user": { - "name": "gabriel", - "password": "test", - "tenantId": tenant_id, - "enabled": True, - "email": None, - } - } - - user_id = uuid.uuid4().hex - resp_body = { - "user": { - "name": "gabriel", - "enabled": True, - "tenantId": tenant_id, - "id": user_id, - "password": "test", - } - } - - self.stub_url('POST', ['users'], json=resp_body) - - user = self.client.users.create( - req_body['user']['name'], - req_body['user']['password'], - tenant_id=req_body['user']['tenantId'], - enabled=req_body['user']['enabled']) - self.assertIsInstance(user, users.User) - self.assertEqual(user.id, user_id) - self.assertEqual(user.name, "gabriel") - self.assertRequestBodyIs(json=req_body) - - def test_create_user_without_password(self): - user_name = 'test' - user_id = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - user_enabled = True - req_body = { - 'user': { - 'name': user_name, - 'password': None, - 'tenantId': tenant_id, - 'enabled': user_enabled, - 'email': None, - } - } - resp_body = { - 'user': { - 'name': user_name, - 'enabled': user_enabled, - 'tenantId': tenant_id, - 'id': user_id, - } - } - - self.stub_url('POST', ['users'], json=resp_body) - - user = self.client.users.create(user_name, tenant_id=tenant_id, - enabled=user_enabled) - self.assertIsInstance(user, users.User) - self.assertEqual(user_id, user.id) - self.assertEqual(user_name, user.name) - self.assertRequestBodyIs(json=req_body) - - def test_delete(self): - self.stub_url('DELETE', ['users', self.ADMIN_USER_ID], status_code=204) - self.client.users.delete(self.ADMIN_USER_ID) - - def test_get(self): - self.stub_url('GET', ['users', self.ADMIN_USER_ID], - json={'user': self.TEST_USERS['users']['values'][0]}) - - u = self.client.users.get(self.ADMIN_USER_ID) - self.assertIsInstance(u, users.User) - self.assertEqual(u.id, self.ADMIN_USER_ID) - self.assertEqual(u.name, 'admin') - - def test_list(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list() - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_list_limit(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list(limit=1) - self.assertQueryStringIs('limit=1') - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_list_marker(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list(marker='foo') - self.assertQueryStringIs('marker=foo') - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_list_limit_marker(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list(limit=1, marker='foo') - - self.assertQueryStringIs('marker=foo&limit=1') - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_update(self): - req_1 = { - "user": { - "email": "gabriel@example.com", - "name": "gabriel", - } - } - password = uuid.uuid4().hex - req_2 = { - "user": { - "password": password, - } - } - tenant_id = uuid.uuid4().hex - req_3 = { - "user": { - "tenantId": tenant_id, - } - } - req_4 = { - "user": { - "enabled": False, - } - } - - self.stub_url('PUT', ['users', self.DEMO_USER_ID], json=req_1) - self.stub_url('PUT', - ['users', self.DEMO_USER_ID, 'OS-KSADM', 'password'], - json=req_2) - self.stub_url('PUT', - ['users', self.DEMO_USER_ID, 'OS-KSADM', 'tenant'], - json=req_3) - self.stub_url('PUT', - ['users', self.DEMO_USER_ID, 'OS-KSADM', 'enabled'], - json=req_4) - - self.client.users.update(self.DEMO_USER_ID, - name='gabriel', - email='gabriel@example.com') - self.assertRequestBodyIs(json=req_1) - self.client.users.update_password(self.DEMO_USER_ID, password) - self.assertRequestBodyIs(json=req_2) - self.client.users.update_tenant(self.DEMO_USER_ID, tenant_id) - self.assertRequestBodyIs(json=req_3) - self.client.users.update_enabled(self.DEMO_USER_ID, False) - self.assertRequestBodyIs(json=req_4) - self.assertNotIn(password, self.logger.output) - - def test_update_own_password(self): - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - req_body = { - 'user': { - 'password': new_password, - 'original_password': old_password - } - } - resp_body = { - 'access': {} - } - self.stub_url('PATCH', - ['OS-KSCRUD', 'users', self.TEST_USER_ID], - json=resp_body) - - self.client.users.update_own_password(old_password, new_password) - self.assertRequestBodyIs(json=req_body) - self.assertNotIn(old_password, self.logger.output) - self.assertNotIn(new_password, self.logger.output) - - def test_user_role_listing(self): - user_id = uuid.uuid4().hex - role_id1 = uuid.uuid4().hex - role_id2 = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - - user_resp = { - 'user': { - 'id': user_id, - 'email': uuid.uuid4().hex, - 'name': uuid.uuid4().hex, - } - } - - roles_resp = { - 'roles': { - 'values': [ - { - 'name': uuid.uuid4().hex, - 'id': role_id1, - }, - { - 'name': uuid.uuid4().hex, - 'id': role_id2, - } - ] - } - } - - self.stub_url('GET', ['users', user_id], json=user_resp) - self.stub_url('GET', - ['tenants', tenant_id, 'users', user_id, 'roles'], - json=roles_resp) - - user = self.client.users.get(user_id) - role_objs = user.list_roles(tenant_id) - - for r in role_objs: - self.assertIsInstance(r, roles.Role) - - self.assertEqual(set([role_id1, role_id2]), - set([r.id for r in role_objs])) diff --git a/keystoneclient/tests/unit/v2_0/utils.py b/keystoneclient/tests/unit/v2_0/utils.py deleted file mode 100644 index 6532d71b..00000000 --- a/keystoneclient/tests/unit/v2_0/utils.py +++ /dev/null @@ -1,90 +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.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils - - -class UnauthenticatedTestCase(utils.TestCase): - """Class used as base for unauthenticated calls.""" - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v2.0') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v2.0') - - -class TestCase(UnauthenticatedTestCase): - - TEST_ADMIN_IDENTITY_ENDPOINT = "http://127.0.0.1:35357/v2.0" - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "adminURL": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:8774/v1.0", - "publicURL": "http://cdn.admin-nets.local:8774/v1.0/" - }], - "type": "nova_compat", - "name": "nova_compat" - }, { - "endpoints": [{ - "adminURL": "http://nova/novapi/admin", - "region": "RegionOne", - "internalURL": "http://nova/novapi/internal", - "publicURL": "http://nova/novapi/public" - }], - "type": "compute", - "name": "nova" - }, { - "endpoints": [{ - "adminURL": "http://glance/glanceapi/admin", - "region": "RegionOne", - "internalURL": "http://glance/glanceapi/internal", - "publicURL": "http://glance/glanceapi/public" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "adminURL": TEST_ADMIN_IDENTITY_ENDPOINT, - "region": "RegionOne", - "internalURL": "http://127.0.0.1:5000/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - }], - "type": "identity", - "name": "keystone" - }, { - "endpoints": [{ - "adminURL": "http://swift/swiftapi/admin", - "region": "RegionOne", - "internalURL": "http://swift/swiftapi/internal", - "publicURL": "http://swift/swiftapi/public" - }], - "type": "object-store", - "name": "swift" - }] - - def stub_auth(self, **kwargs): - self.stub_url('POST', ['tokens'], **kwargs) - - -class ClientTestCase(utils.ClientTestCaseMixin, TestCase): - - scenarios = [ - ('original', - {'client_fixture_class': client_fixtures.OriginalV2}), - ('ksc-session', - {'client_fixture_class': client_fixtures.KscSessionV2}), - ('ksa-session', - {'client_fixture_class': client_fixtures.KsaSessionV2}), - ] diff --git a/keystoneclient/tests/unit/v3/__init__.py b/keystoneclient/tests/unit/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/v3/client_fixtures.py b/keystoneclient/tests/unit/v3/client_fixtures.py deleted file mode 100644 index 8e86208e..00000000 --- a/keystoneclient/tests/unit/v3/client_fixtures.py +++ /dev/null @@ -1,159 +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 __future__ import unicode_literals -import uuid - -from keystoneauth1 import fixture - - -def unscoped_token(**kwargs): - return fixture.V3Token(**kwargs) - - -def domain_scoped_token(**kwargs): - kwargs.setdefault('audit_chain_id', uuid.uuid4().hex) - f = fixture.V3Token(**kwargs) - if not f.domain_id: - f.set_domain_scope() - - f.add_role(name='admin') - f.add_role(name='member') - region = 'RegionOne' - - s = f.add_service('volume') - s.add_standard_endpoints(public='http://public.com:8776/v1/None', - internal='http://internal.com:8776/v1/None', - admin='http://admin.com:8776/v1/None', - region=region) - - s = f.add_service('image') - s.add_standard_endpoints(public='http://public.com:9292/v1', - internal='http://internal:9292/v1', - admin='http://admin:9292/v1', - region=region) - - s = f.add_service('compute') - s.add_standard_endpoints(public='http://public.com:8774/v1.1/None', - internal='http://internal:8774/v1.1/None', - admin='http://admin:8774/v1.1/None', - region=region) - - s = f.add_service('ec2') - s.add_standard_endpoints(public='http://public.com:8773/services/Cloud', - internal='http://internal:8773/services/Cloud', - admin='http://admin:8773/services/Admin', - region=region) - - s = f.add_service('identity') - s.add_standard_endpoints(public='http://public.com:5000/v3', - internal='http://internal:5000/v3', - admin='http://admin:35357/v3', - region=region) - - return f - - -def project_scoped_token(**kwargs): - kwargs.setdefault('audit_chain_id', uuid.uuid4().hex) - f = fixture.V3Token(**kwargs) - - if not f.project_id: - f.set_project_scope() - - f.add_role(name='admin') - f.add_role(name='member') - - region = 'RegionOne' - tenant = '225da22d3ce34b15877ea70b2a575f58' - - s = f.add_service('volume') - s.add_standard_endpoints(public='http://public.com:8776/v1/%s' % tenant, - internal='http://internal:8776/v1/%s' % tenant, - admin='http://admin:8776/v1/%s' % tenant, - region=region) - - s = f.add_service('image') - s.add_standard_endpoints(public='http://public.com:9292/v1', - internal='http://internal:9292/v1', - admin='http://admin:9292/v1', - region=region) - - s = f.add_service('compute') - s.add_standard_endpoints(public='http://public.com:8774/v2/%s' % tenant, - internal='http://internal:8774/v2/%s' % tenant, - admin='http://admin:8774/v2/%s' % tenant, - region=region) - - s = f.add_service('ec2') - s.add_standard_endpoints(public='http://public.com:8773/services/Cloud', - internal='http://internal:8773/services/Cloud', - admin='http://admin:8773/services/Admin', - region=region) - - s = f.add_service('identity') - s.add_standard_endpoints(public='http://public.com:5000/v3', - internal='http://internal:5000/v3', - admin='http://admin:35357/v3', - region=region) - - return f - - -AUTH_SUBJECT_TOKEN = uuid.uuid4().hex - -AUTH_RESPONSE_HEADERS = { - 'X-Subject-Token': AUTH_SUBJECT_TOKEN, -} - - -def auth_response_body(): - f = fixture.V3Token(audit_chain_id=uuid.uuid4().hex) - f.set_project_scope() - - f.add_role(name='admin') - f.add_role(name='member') - - s = f.add_service('compute', name='nova') - s.add_standard_endpoints( - public='https://compute.north.host/novapi/public', - internal='https://compute.north.host/novapi/internal', - admin='https://compute.north.host/novapi/admin', - region='North') - - s = f.add_service('object-store', name='swift') - s.add_standard_endpoints( - public='http://swift.north.host/swiftapi/public', - internal='http://swift.north.host/swiftapi/internal', - admin='http://swift.north.host/swiftapi/admin', - region='South') - - s = f.add_service('image', name='glance') - s.add_standard_endpoints( - public='http://glance.north.host/glanceapi/public', - internal='http://glance.north.host/glanceapi/internal', - admin='http://glance.north.host/glanceapi/admin', - region='North') - - s.add_standard_endpoints( - public='http://glance.south.host/glanceapi/public', - internal='http://glance.south.host/glanceapi/internal', - admin='http://glance.south.host/glanceapi/admin', - region='South') - - return f - - -def trust_token(): - f = fixture.V3Token(audit_chain_id=uuid.uuid4().hex) - f.set_trust_scope() - return f diff --git a/keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml b/keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml deleted file mode 100644 index 487bcac5..00000000 --- a/keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal - urn:uuid:487c064b-b7c6-4654-b4d4-715f9961170e - - - 2014-08-05T18:36:14.235Z - 2014-08-05T18:41:14.235Z - - - - - - - - 2014-08-05T18:36:14.063Z - 2014-08-05T19:36:14.063Z - - - - https://ltartari2.cern.ch:5000/Shibboleth.sso/ADFS - - - - - - - https://ltartari2.cern.ch:5000/Shibboleth.sso/ADFS - - - - - marek.denis@cern.ch - - urn:oasis:names:tc:SAML:1.0:cm:bearer - - - - marek.denis@cern.ch - - - marek.denis@cern.ch - - - madenis - - - CERN Users - - - Domain Users - occupants-bldg-31 - CERN-Direct-Employees - ca-dev-allowed - cernts-cerntstest-users - staf-fell-pjas-at-cern - ELG-CERN - student-club-new-members - pawel-dynamic-test-82 - - - Marek Kamil Denis - - - +5555555 - - - 31S-013 - - - Marek Kamil - - - Denis - - - CERN Registered - - - CERN - - - Normal - - - - - marek.denis@cern.ch - - urn:oasis:names:tc:SAML:1.0:cm:bearer - - - - - - - - - - - - - - EaZ/2d0KAY5un9akV3++Npyk6hBc8JuTYs2S3lSxUeQ= - - - CxYiYvNsbedhHdmDbb9YQCBy6Ppus3bNJdw2g2HLq0VU2yRhv23mUW05I89Hs4yG4OcCo0uOZ3zaeNFbSNXMW+Mr996tAXtujKjgyrCXNJAToE+gwltvGxwY1EluSbe3IzoSM3Ao87mKhxGOSzlDhuN7dQ9Rv6l/J4gUjbOO5SIX4pdZ6mVF7cHEfe9x+H8Lg15YjnElQUEaPi+NSW5jYTdtIpsB4ORxJvALuSt6+4doDYc9wuwBiWkEdnBHAQBINoKpAV2oy0/C85SBX3IdRhxUznmL5yEUmf8JvPccXecMPqJow0L43mnCdu74xPwU0as3MNfYQ10kLvHXHfIExg== - - - MIIIEjCCBfqgAwIBAgIKLYgjvQAAAAAAMDANBgkqhkiG9w0BAQsFADBRMRIwEAYKCZImiZPyLGQBGRYCY2gxFDASBgoJkiaJk/IsZAEZFgRjZXJuMSUwIwYDVQQDExxDRVJOIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMTEwODA4Mzg1NVoXDTIzMDcyOTA5MTkzOFowVjESMBAGCgmSJomT8ixkARkWAmNoMRQwEgYKCZImiZPyLGQBGRYEY2VybjESMBAGA1UECxMJY29tcHV0ZXJzMRYwFAYDVQQDEw1sb2dpbi5jZXJuLmNoMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6t1C0SGlLddL2M+ltffGioTnDT3eztOxlA9bAGuvB8/Rjym8en6+ET9boM02CyoR5Vpn8iElXVWccAExPIQEq70D6LPe86vb+tYhuKPeLfuICN9Z0SMQ4f+57vk61Co1/uw/8kPvXlyd+Ai8Dsn/G0hpH67bBI9VOQKfpJqclcSJuSlUB5PJffvMUpr29B0eRx8LKFnIHbDILSu6nVbFLcadtWIjbYvoKorXg3J6urtkz+zEDeYMTvA6ZGOFf/Xy5eGtroSq9csSC976tx+umKEPhXBA9AcpiCV9Cj5axN03Aaa+iTE36jpnjcd9d02dy5Q9jE2nUN6KXnB6qF6eQIDAQABo4ID5TCCA+EwPQYJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIg73QCYLtjQ2G7Ysrgd71N4WA0GIehd2yb4Wu9TkCAWQCARkwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIFoDBoBgNVHSAEYTBfMF0GCisGAQQBYAoEAQEwTzBNBggrBgEFBQcCARZBaHR0cDovL2NhLWRvY3MuY2Vybi5jaC9jYS1kb2NzL2NwLWNwcy9jZXJuLXRydXN0ZWQtY2EyLWNwLWNwcy5wZGYwJwYJKwYBBAGCNxUKBBowGDAKBggrBgEFBQcDAjAKBggrBgEFBQcDATAdBgNVHQ4EFgQUqtJcwUXasyM6sRaO5nCMFoFDenMwGAYDVR0RBBEwD4INbG9naW4uY2Vybi5jaDAfBgNVHSMEGDAWgBQdkBnqyM7MPI0UsUzZ7BTiYUADYTCCASoGA1UdHwSCASEwggEdMIIBGaCCARWgggERhkdodHRwOi8vY2FmaWxlcy5jZXJuLmNoL2NhZmlsZXMvY3JsL0NFUk4lMjBDZXJ0aWZpY2F0aW9uJTIwQXV0aG9yaXR5LmNybIaBxWxkYXA6Ly8vQ049Q0VSTiUyMENlcnRpZmljYXRpb24lMjBBdXRob3JpdHksQ049Q0VSTlBLSTA3LENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWNlcm4sREM9Y2g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIBVAYIKwYBBQUHAQEEggFGMIIBQjBcBggrBgEFBQcwAoZQaHR0cDovL2NhZmlsZXMuY2Vybi5jaC9jYWZpbGVzL2NlcnRpZmljYXRlcy9DRVJOJTIwQ2VydGlmaWNhdGlvbiUyMEF1dGhvcml0eS5jcnQwgbsGCCsGAQUFBzAChoGubGRhcDovLy9DTj1DRVJOJTIwQ2VydGlmaWNhdGlvbiUyMEF1dGhvcml0eSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jZXJuLERDPWNoP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jZXJuLmNoL29jc3AwDQYJKoZIhvcNAQELBQADggIBAGKZ3bknTCfNuh4TMaL3PuvBFjU8LQ5NKY9GLZvY2ibYMRk5Is6eWRgyUsy1UJRQdaQQPnnysqrGq8VRw/NIFotBBsA978/+jj7v4e5Kr4o8HvwAQNLBxNmF6XkDytpLL701FcNEGRqIsoIhNzihi2VBADLC9HxljEyPT52IR767TMk/+xTOqClceq3sq6WRD4m+xaWRUJyOhn+Pqr+wbhXIw4wzHC6X0hcLj8P9Povtm6VmKkN9JPuymMo/0+zSrUt2+TYfmbbEKYJSP0+sceQ76IKxxmSdKAr1qDNE8v+c3DvPM2PKmfivwaV2l44FdP8ulzqTgphkYcN1daa9Oc+qJeyu/eL7xWzk6Zq5R+jVrMlM0p1y2XczI7Hoc96TMOcbVnwgMcVqRM9p57VItn6XubYPR0C33i1yUZjkWbIfqEjq6Vev6lVgngOyzu+hqC/8SDyORA3dlF9aZOD13kPZdF/JRphHREQtaRydAiYRlE/WHTvOcY52jujDftUR6oY0eWaWkwSHbX+kDFx8IlR8UtQCUgkGHBGwnOYLIGu7SRDGSfOBOiVhxKoHWVk/pL6eKY2SkmyOmmgO4JnQGg95qeAOMG/EQZt/2x8GAavUqGvYy9dPFwFf08678hQqkjNSuex7UD0ku8OP1QKvpP44l6vZhFc6A5XqjdU9lus1 - - - - - - - - _c9e77bc4-a81b-4da7-88c2-72a6ba376d3f - - - - - _c9e77bc4-a81b-4da7-88c2-72a6ba376d3f - - - urn:oasis:names:tc:SAML:1.0:assertion - http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue - http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer - - - - \ No newline at end of file diff --git a/keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml b/keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml deleted file mode 100644 index 913252e7..00000000 --- a/keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - http://www.w3.org/2005/08/addressing/soap/fault - urn:uuid:89c47849-2622-4cdc-bb06-1d46c89ed12d - - - - - s:Sender - - a:FailedAuthentication - - - - At least one security token in the message could not be validated. - - - - \ No newline at end of file diff --git a/keystoneclient/tests/unit/v3/saml2_fixtures.py b/keystoneclient/tests/unit/v3/saml2_fixtures.py deleted file mode 100644 index 3cf2e772..00000000 --- a/keystoneclient/tests/unit/v3/saml2_fixtures.py +++ /dev/null @@ -1,281 +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. - -import six - -SP_SOAP_RESPONSE = six.b(""" - - - - -https://openstack4.local/shibboleth - - - - - -ss:mem:6f1f20fafbb38433467e9d477df67615 - - - https://openstack4.local/shibboleth - - - - -""") - - -SAML2_ASSERTION = six.b(""" - - - - - x= - - - - - -https://idp.testshib.org/idp/shibboleth - - - - - - - - - - - - - - -VALUE== - - -VALUE= - - -""") - -UNSCOPED_TOKEN_HEADER = 'UNSCOPED_TOKEN' - -UNSCOPED_TOKEN = { - "token": { - "issued_at": "2014-06-09T09:48:59.643406Z", - "extras": {}, - "methods": ["saml2"], - "expires_at": "2014-06-09T10:48:59.643375Z", - "user": { - "OS-FEDERATION": { - "identity_provider": { - "id": "testshib" - }, - "protocol": { - "id": "saml2" - }, - "groups": [ - {"id": "1764fa5cf69a49a4918131de5ce4af9a"} - ] - }, - "id": "testhib%20user", - "name": "testhib user" - } - } -} - -PROJECTS = { - "projects": [ - { - "domain_id": "37ef61", - "enabled": 'true', - "id": "12d706", - "links": { - "self": "http://identity:35357/v3/projects/12d706" - }, - "name": "a project name" - }, - { - "domain_id": "37ef61", - "enabled": 'true', - "id": "9ca0eb", - "links": { - "self": "http://identity:35357/v3/projects/9ca0eb" - }, - "name": "another project" - } - ], - "links": { - "self": "http://identity:35357/v3/auth/projects", - "previous": 'null', - "next": 'null' - } -} - -DOMAINS = { - "domains": [ - { - "description": "desc of domain", - "enabled": 'true', - "id": "37ef61", - "links": { - "self": "http://identity:35357/v3/domains/37ef61" - }, - "name": "my domain" - } - ], - "links": { - "self": "http://identity:35357/v3/auth/domains", - "previous": 'null', - "next": 'null' - } -} - -SAML_ENCODING = "" - -TOKEN_SAML_RESPONSE = """ - - - http://keystone.idp/v3/OS-FEDERATION/saml2/idp - - - - - - - http://keystone.idp/v3/OS-FEDERATION/saml2/idp - - - - - - - - - - - - 0KH2CxdkfzU+6eiRhTC+mbObUKI= - - - - - m2jh5gDvX/1k+4uKtbb08CHp2b9UWsLw - - - - ... - - - - - admin - - - - - - - - urn:oasis:names:tc:SAML:2.0:ac:classes:Password - - - http://keystone.idp/v3/OS-FEDERATION/saml2/idp - - - - - - admin - - - admin - - - admin - - - - -""" - -TOKEN_BASED_SAML = ''.join([SAML_ENCODING, TOKEN_SAML_RESPONSE]) - -ECP_ENVELOPE = """ - - - - ss:mem:1ddfe8b0f58341a5a840d2e8717b0737 - - - - {0} - - -""".format(TOKEN_SAML_RESPONSE) - -TOKEN_BASED_ECP = ''.join([SAML_ENCODING, ECP_ENVELOPE]) diff --git a/keystoneclient/tests/unit/v3/test_access.py b/keystoneclient/tests/unit/v3/test_access.py deleted file mode 100644 index 26ca8f15..00000000 --- a/keystoneclient/tests/unit/v3/test_access.py +++ /dev/null @@ -1,211 +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. - -import datetime -import uuid - -from keystoneauth1 import fixture -from oslo_utils import timeutils - -from keystoneclient import access -from keystoneclient.tests.unit import utils as test_utils -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -TOKEN_RESPONSE = test_utils.test_response( - headers=client_fixtures.AUTH_RESPONSE_HEADERS -) -UNSCOPED_TOKEN = client_fixtures.unscoped_token() -DOMAIN_SCOPED_TOKEN = client_fixtures.domain_scoped_token() -PROJECT_SCOPED_TOKEN = client_fixtures.project_scoped_token() - - -class AccessInfoTest(utils.TestCase): - def test_building_unscoped_accessinfo(self): - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=UNSCOPED_TOKEN) - - self.assertTrue(auth_ref) - self.assertIn('methods', auth_ref) - self.assertNotIn('catalog', auth_ref) - - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, - auth_ref.auth_token) - self.assertEqual(UNSCOPED_TOKEN.user_name, auth_ref.username) - self.assertEqual(UNSCOPED_TOKEN.user_id, auth_ref.user_id) - - self.assertEqual(auth_ref.role_ids, []) - self.assertEqual(auth_ref.role_names, []) - - self.assertIsNone(auth_ref.project_name) - self.assertIsNone(auth_ref.project_id) - - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.auth_url) - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.management_url) - - self.assertFalse(auth_ref.domain_scoped) - self.assertFalse(auth_ref.project_scoped) - - self.assertEqual(UNSCOPED_TOKEN.user_domain_id, - auth_ref.user_domain_id) - self.assertEqual(UNSCOPED_TOKEN.user_domain_name, - auth_ref.user_domain_name) - - self.assertIsNone(auth_ref.project_domain_id) - self.assertIsNone(auth_ref.project_domain_name) - - self.assertEqual(auth_ref.expires, timeutils.parse_isotime( - UNSCOPED_TOKEN['token']['expires_at'])) - self.assertEqual(auth_ref.issued, timeutils.parse_isotime( - UNSCOPED_TOKEN['token']['issued_at'])) - - self.assertEqual(auth_ref.expires, UNSCOPED_TOKEN.expires) - self.assertEqual(auth_ref.issued, UNSCOPED_TOKEN.issued) - - self.assertEqual(auth_ref.audit_id, UNSCOPED_TOKEN.audit_id) - self.assertIsNone(auth_ref.audit_chain_id) - self.assertIsNone(UNSCOPED_TOKEN.audit_chain_id) - - def test_will_expire_soon(self): - expires = timeutils.utcnow() + datetime.timedelta(minutes=5) - UNSCOPED_TOKEN['token']['expires_at'] = expires.isoformat() - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=UNSCOPED_TOKEN) - self.assertFalse(auth_ref.will_expire_soon(stale_duration=120)) - self.assertTrue(auth_ref.will_expire_soon(stale_duration=301)) - self.assertFalse(auth_ref.will_expire_soon()) - - def test_building_domain_scoped_accessinfo(self): - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=DOMAIN_SCOPED_TOKEN) - - self.assertTrue(auth_ref) - self.assertIn('methods', auth_ref) - self.assertIn('catalog', auth_ref) - self.assertTrue(auth_ref['catalog']) - - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, - auth_ref.auth_token) - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_name, auth_ref.username) - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_id, auth_ref.user_id) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.role_ids, auth_ref.role_ids) - self.assertEqual(DOMAIN_SCOPED_TOKEN.role_names, auth_ref.role_names) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.domain_name, auth_ref.domain_name) - self.assertEqual(DOMAIN_SCOPED_TOKEN.domain_id, auth_ref.domain_id) - - self.assertIsNone(auth_ref.project_name) - self.assertIsNone(auth_ref.project_id) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_domain_id, - auth_ref.user_domain_id) - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_domain_name, - auth_ref.user_domain_name) - - self.assertIsNone(auth_ref.project_domain_id) - self.assertIsNone(auth_ref.project_domain_name) - - self.assertTrue(auth_ref.domain_scoped) - self.assertFalse(auth_ref.project_scoped) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.audit_id, auth_ref.audit_id) - self.assertEqual(DOMAIN_SCOPED_TOKEN.audit_chain_id, - auth_ref.audit_chain_id) - - def test_building_project_scoped_accessinfo(self): - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=PROJECT_SCOPED_TOKEN) - - self.assertTrue(auth_ref) - self.assertIn('methods', auth_ref) - self.assertIn('catalog', auth_ref) - self.assertTrue(auth_ref['catalog']) - - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, - auth_ref.auth_token) - self.assertEqual(PROJECT_SCOPED_TOKEN.user_name, auth_ref.username) - self.assertEqual(PROJECT_SCOPED_TOKEN.user_id, auth_ref.user_id) - - self.assertEqual(PROJECT_SCOPED_TOKEN.role_ids, auth_ref.role_ids) - self.assertEqual(PROJECT_SCOPED_TOKEN.role_names, auth_ref.role_names) - - self.assertIsNone(auth_ref.domain_name) - self.assertIsNone(auth_ref.domain_id) - - self.assertEqual(PROJECT_SCOPED_TOKEN.project_name, - auth_ref.project_name) - self.assertEqual(PROJECT_SCOPED_TOKEN.project_id, auth_ref.project_id) - - self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) - self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.auth_url, - ('http://public.com:5000/v3',)) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.management_url, - ('http://admin:35357/v3',)) - - self.assertEqual(PROJECT_SCOPED_TOKEN.project_domain_id, - auth_ref.project_domain_id) - self.assertEqual(PROJECT_SCOPED_TOKEN.project_domain_name, - auth_ref.project_domain_name) - - self.assertEqual(PROJECT_SCOPED_TOKEN.user_domain_id, - auth_ref.user_domain_id) - self.assertEqual(PROJECT_SCOPED_TOKEN.user_domain_name, - auth_ref.user_domain_name) - - self.assertFalse(auth_ref.domain_scoped) - self.assertTrue(auth_ref.project_scoped) - - self.assertEqual(PROJECT_SCOPED_TOKEN.audit_id, auth_ref.audit_id) - self.assertEqual(PROJECT_SCOPED_TOKEN.audit_chain_id, - auth_ref.audit_chain_id) - - def test_oauth_access(self): - consumer_id = uuid.uuid4().hex - access_token_id = uuid.uuid4().hex - - token = fixture.V3Token() - token.set_project_scope() - token.set_oauth(access_token_id=access_token_id, - consumer_id=consumer_id) - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual(consumer_id, auth_ref.oauth_consumer_id) - self.assertEqual(access_token_id, auth_ref.oauth_access_token_id) - - self.assertEqual(consumer_id, auth_ref['OS-OAUTH1']['consumer_id']) - self.assertEqual(access_token_id, - auth_ref['OS-OAUTH1']['access_token_id']) - - def test_override_auth_token(self): - token = fixture.V3Token() - token.set_project_scope() - - new_auth_token = uuid.uuid4().hex - auth_ref = access.AccessInfo.factory(body=token, - auth_token=new_auth_token) - self.assertEqual(new_auth_token, auth_ref.auth_token) - - def test_federated_property_standard_token(self): - """Check if is_federated property returns expected value.""" - token = fixture.V3Token() - token.set_project_scope() - auth_ref = access.AccessInfo.factory(body=token) - self.assertFalse(auth_ref.is_federated) diff --git a/keystoneclient/tests/unit/v3/test_auth.py b/keystoneclient/tests/unit/v3/test_auth.py deleted file mode 100644 index 6549080f..00000000 --- a/keystoneclient/tests/unit/v3/test_auth.py +++ /dev/null @@ -1,372 +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 oslo_serialization import jsonutils -from testtools import testcase - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import client - - -class AuthenticateAgainstKeystoneTests(utils.TestCase): - def setUp(self): - super(AuthenticateAgainstKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "token": { - "methods": [ - "token", - "password" - ], - - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_TENANT_ID, - "name": self.TEST_TENANT_NAME - }, - "user": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_USER, - "name": self.TEST_USER - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": self.TEST_SERVICE_CATALOG - }, - } - self.TEST_REQUEST_BODY = { - "auth": { - "identity": { - "methods": ["password"], - "password": { - "user": { - "domain": { - "name": self.TEST_DOMAIN_NAME - }, - "name": self.TEST_USER, - "password": self.TEST_TOKEN - } - } - }, - "scope": { - "project": { - "id": self.TEST_TENANT_ID - }, - } - } - } - self.TEST_REQUEST_HEADERS = { - 'Content-Type': 'application/json', - 'User-Agent': 'python-keystoneclient' - } - self.TEST_RESPONSE_HEADERS = { - 'X-Subject-Token': self.TEST_TOKEN - } - - def test_authenticate_success(self): - TEST_TOKEN = "abcdef" - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password']['user']['domain'] - del ident['password']['user']['name'] - ident['password']['user']['id'] = self.TEST_USER - - self.stub_auth(json=self.TEST_RESPONSE_DICT, subject_token=TEST_TOKEN) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_id=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, TEST_TOKEN) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_failure(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - ident['password']['user']['password'] = 'bad_key' - error = {"unauthorized": {"message": "Unauthorized", - "code": "401"}} - - self.stub_auth(status_code=401, json=error) - - with testcase.ExpectedException(exceptions.Unauthorized): - with self.deprecations.expect_deprecations_here(): - client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password="bad_key", - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_redirect(self): - headers = {'Location': self.TEST_ADMIN_URL + '/auth/tokens'} - self.stub_auth(status_code=305, text='Use proxy', headers=headers) - - self.stub_auth(json=self.TEST_RESPONSE_DICT, - base_url=self.TEST_ADMIN_URL) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - - def test_authenticate_success_domain_username_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - - def test_authenticate_success_userid_password_domain_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password']['user']['domain'] - del ident['password']['user']['name'] - ident['password']['user']['id'] = self.TEST_USER - - scope = self.TEST_REQUEST_BODY['auth']['scope'] - del scope['project'] - scope['domain'] = {} - scope['domain']['id'] = self.TEST_DOMAIN_ID - - token = self.TEST_RESPONSE_DICT['token'] - del token['project'] - token['domain'] = {} - token['domain']['id'] = self.TEST_DOMAIN_ID - token['domain']['name'] = self.TEST_DOMAIN_NAME - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_id=self.TEST_USER, - password=self.TEST_TOKEN, - domain_id=self.TEST_DOMAIN_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_domain_id, - self.TEST_DOMAIN_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_userid_password_project_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password']['user']['domain'] - del ident['password']['user']['name'] - ident['password']['user']['id'] = self.TEST_USER - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_id=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_tenant_id, - self.TEST_TENANT_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_password_unscoped(self): - del self.TEST_RESPONSE_DICT['token']['catalog'] - del self.TEST_REQUEST_BODY['auth']['scope'] - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertNotIn('catalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_url_token_authentication(self): - fake_token = 'fake_token' - fake_url = '/fake-url' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(auth_url=self.TEST_URL, - token=fake_token) - body = jsonutils.loads(self.requests_mock.last_request.body) - self.assertEqual(body['auth']['identity']['token']['id'], fake_token) - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - def test_authenticate_success_token_domain_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password'] - ident['methods'] = ['token'] - ident['token'] = {} - ident['token']['id'] = self.TEST_TOKEN - - scope = self.TEST_REQUEST_BODY['auth']['scope'] - del scope['project'] - scope['domain'] = {} - scope['domain']['id'] = self.TEST_DOMAIN_ID - - token = self.TEST_RESPONSE_DICT['token'] - del token['project'] - token['domain'] = {} - token['domain']['id'] = self.TEST_DOMAIN_ID - token['domain']['name'] = self.TEST_DOMAIN_NAME - - self.TEST_REQUEST_HEADERS['X-Auth-Token'] = self.TEST_TOKEN - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - domain_id=self.TEST_DOMAIN_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_domain_id, - self.TEST_DOMAIN_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_project_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password'] - ident['methods'] = ['token'] - ident['token'] = {} - ident['token']['id'] = self.TEST_TOKEN - self.TEST_REQUEST_HEADERS['X-Auth-Token'] = self.TEST_TOKEN - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_tenant_id, - self.TEST_TENANT_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_unscoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password'] - ident['methods'] = ['token'] - ident['token'] = {} - ident['token']['id'] = self.TEST_TOKEN - del self.TEST_REQUEST_BODY['auth']['scope'] - del self.TEST_RESPONSE_DICT['token']['catalog'] - self.TEST_REQUEST_HEADERS['X-Auth-Token'] = self.TEST_TOKEN - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertNotIn('catalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_allow_override_of_auth_token(self): - fake_url = '/fake-url' - fake_token = 'fake_token' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - - self.assertEqual(cl.auth_token, self.TEST_TOKEN) - - # the token returned from the authentication will be used - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - # then override that token and the new token shall be used - cl.auth_token = fake_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(fake_token, token) - - # if we clear that overridden token then we fall back to the original - del cl.auth_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) diff --git a/keystoneclient/tests/unit/v3/test_auth_manager.py b/keystoneclient/tests/unit/v3/test_auth_manager.py deleted file mode 100644 index 18579607..00000000 --- a/keystoneclient/tests/unit/v3/test_auth_manager.py +++ /dev/null @@ -1,64 +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. - -import uuid - -from keystoneauth1 import fixture - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import auth - - -class AuthProjectsTest(utils.ClientTestCase): - - def setUp(self): - super(AuthProjectsTest, self).setUp() - - self.v3token = fixture.V3Token() - self.stub_auth(json=self.v3token) - - self.stub_url('GET', - [], - json={'version': fixture.V3Discovery(self.TEST_URL)}) - - def create_resource(self, id=None, name=None, **kwargs): - kwargs['id'] = id or uuid.uuid4().hex - kwargs['name'] = name or uuid.uuid4().hex - return kwargs - - def test_get_projects(self): - body = {'projects': [self.create_resource(), - self.create_resource(), - self.create_resource()]} - - self.stub_url('GET', ['auth', 'projects'], json=body) - - projects = self.client.auth.projects() - - self.assertEqual(3, len(projects)) - - for p in projects: - self.assertIsInstance(p, auth.Project) - - def test_get_domains(self): - body = {'domains': [self.create_resource(), - self.create_resource(), - self.create_resource()]} - - self.stub_url('GET', ['auth', 'domains'], json=body) - - domains = self.client.auth.domains() - - self.assertEqual(3, len(domains)) - - for d in domains: - self.assertIsInstance(d, auth.Domain) diff --git a/keystoneclient/tests/unit/v3/test_auth_oidc.py b/keystoneclient/tests/unit/v3/test_auth_oidc.py deleted file mode 100644 index b0140dd0..00000000 --- a/keystoneclient/tests/unit/v3/test_auth_oidc.py +++ /dev/null @@ -1,188 +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. - -import uuid - -from oslo_config import fixture as config -from six.moves import urllib -import testtools - -from keystoneclient.auth import conf -from keystoneclient.contrib.auth.v3 import oidc -from keystoneclient import session -from keystoneclient.tests.unit.v3 import utils - - -ACCESS_TOKEN_ENDPOINT_RESP = {"access_token": "z5H1ITZLlJVDHQXqJun", - "token_type": "bearer", - "expires_in": 3599, - "scope": "profile", - "refresh_token": "DCERsh83IAhu9bhavrp"} - -KEYSTONE_TOKEN_VALUE = uuid.uuid4().hex -UNSCOPED_TOKEN = { - "token": { - "issued_at": "2014-06-09T09:48:59.643406Z", - "extras": {}, - "methods": ["oidc"], - "expires_at": "2014-06-09T10:48:59.643375Z", - "user": { - "OS-FEDERATION": { - "identity_provider": { - "id": "bluepages" - }, - "protocol": { - "id": "oidc" - }, - "groups": [ - {"id": "1764fa5cf69a49a4918131de5ce4af9a"} - ] - }, - "id": "oidc_user%40example.com", - "name": "oidc_user@example.com" - } - } -} - - -class AuthenticateOIDCTests(utils.TestCase): - - GROUP = 'auth' - - def setUp(self): - super(AuthenticateOIDCTests, self).setUp() - - self.deprecations.expect_deprecations() - - self.conf_fixture = self.useFixture(config.Config()) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.session = session.Session() - - self.IDENTITY_PROVIDER = 'bluepages' - self.PROTOCOL = 'oidc' - self.USER_NAME = 'oidc_user@example.com' - self.PASSWORD = uuid.uuid4().hex - self.CLIENT_ID = uuid.uuid4().hex - self.CLIENT_SECRET = uuid.uuid4().hex - self.ACCESS_TOKEN_ENDPOINT = 'https://localhost:8020/oidc/token' - self.FEDERATION_AUTH_URL = '%s/%s' % ( - self.TEST_URL, - 'OS-FEDERATION/identity_providers/bluepages/protocols/oidc/auth') - - self.oidcplugin = oidc.OidcPassword( - self.TEST_URL, - self.IDENTITY_PROVIDER, - self.PROTOCOL, - username=self.USER_NAME, - password=self.PASSWORD, - client_id=self.CLIENT_ID, - client_secret=self.CLIENT_SECRET, - access_token_endpoint=self.ACCESS_TOKEN_ENDPOINT) - - @testtools.skip("TypeError: __init__() got an unexpected keyword" - " argument 'project_name'") - def test_conf_params(self): - """Ensure OpenID Connect config options work.""" - section = uuid.uuid4().hex - identity_provider = uuid.uuid4().hex - protocol = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - client_id = uuid.uuid4().hex - client_secret = uuid.uuid4().hex - access_token_endpoint = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(oidc.OidcPassword.get_options(), - group=section) - self.conf_fixture.config(auth_plugin='v3oidcpassword', - identity_provider=identity_provider, - protocol=protocol, - username=username, - password=password, - client_id=client_id, - client_secret=client_secret, - access_token_endpoint=access_token_endpoint, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertEqual(identity_provider, a.identity_provider) - self.assertEqual(protocol, a.protocol) - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - self.assertEqual(client_id, a.client_id) - self.assertEqual(client_secret, a.client_secret) - self.assertEqual(access_token_endpoint, a.access_token_endpoint) - - def test_initial_call_to_get_access_token(self): - """Test initial call, expect JSON access token.""" - # Mock the output that creates the access token - self.requests_mock.post( - self.ACCESS_TOKEN_ENDPOINT, - json=ACCESS_TOKEN_ENDPOINT_RESP) - - # Prep all the values and send the request - grant_type = 'password' - scope = 'profile email' - client_auth = (self.CLIENT_ID, self.CLIENT_SECRET) - payload = {'grant_type': grant_type, 'username': self.USER_NAME, - 'password': self.PASSWORD, 'scope': scope} - res = self.oidcplugin._get_access_token(self.session, - client_auth, - payload, - self.ACCESS_TOKEN_ENDPOINT) - - # Verify the request matches the expected structure - self.assertEqual(self.ACCESS_TOKEN_ENDPOINT, res.request.url) - self.assertEqual('POST', res.request.method) - encoded_payload = urllib.parse.urlencode(payload) - self.assertEqual(encoded_payload, res.request.body) - - def test_second_call_to_protected_url(self): - """Test subsequent call, expect Keystone token.""" - # Mock the output that creates the keystone token - self.requests_mock.post( - self.FEDERATION_AUTH_URL, - json=UNSCOPED_TOKEN, - headers={'X-Subject-Token': KEYSTONE_TOKEN_VALUE}) - - # Prep all the values and send the request - access_token = uuid.uuid4().hex - headers = {'Authorization': 'Bearer ' + access_token} - res = self.oidcplugin._get_keystone_token(self.session, - headers, - self.FEDERATION_AUTH_URL) - - # Verify the request matches the expected structure - self.assertEqual(self.FEDERATION_AUTH_URL, res.request.url) - self.assertEqual('POST', res.request.method) - self.assertEqual(headers['Authorization'], - res.request.headers['Authorization']) - - def test_end_to_end_workflow(self): - """Test full OpenID Connect workflow.""" - # Mock the output that creates the access token - self.requests_mock.post( - self.ACCESS_TOKEN_ENDPOINT, - json=ACCESS_TOKEN_ENDPOINT_RESP) - - # Mock the output that creates the keystone token - self.requests_mock.post( - self.FEDERATION_AUTH_URL, - json=UNSCOPED_TOKEN, - headers={'X-Subject-Token': KEYSTONE_TOKEN_VALUE}) - - response = self.oidcplugin.get_unscoped_auth_ref(self.session) - self.assertEqual(KEYSTONE_TOKEN_VALUE, response.auth_token) diff --git a/keystoneclient/tests/unit/v3/test_auth_saml2.py b/keystoneclient/tests/unit/v3/test_auth_saml2.py deleted file mode 100644 index b74983af..00000000 --- a/keystoneclient/tests/unit/v3/test_auth_saml2.py +++ /dev/null @@ -1,714 +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. - -import os -import uuid - -from lxml import etree -from oslo_config import fixture as config -import requests -from six.moves import urllib - -from keystoneclient.auth import conf -from keystoneclient.contrib.auth.v3 import saml2 -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import saml2_fixtures -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3.contrib.federation import saml as saml_manager - -ROOTDIR = os.path.dirname(os.path.abspath(__file__)) -XMLDIR = os.path.join(ROOTDIR, 'examples', 'xml/') - - -def make_oneline(s): - return etree.tostring(etree.XML(s)).replace(b'\n', b'') - - -def _load_xml(filename): - with open(XMLDIR + filename, 'rb') as f: - return make_oneline(f.read()) - - -class AuthenticateviaSAML2Tests(utils.TestCase): - - GROUP = 'auth' - - class _AuthenticatedResponse(object): - headers = { - 'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER - } - - def json(self): - return saml2_fixtures.UNSCOPED_TOKEN - - class _AuthenticatedResponseInvalidJson(_AuthenticatedResponse): - - def json(self): - raise ValueError() - - class _AuthentiatedResponseMissingTokenID(_AuthenticatedResponse): - headers = {} - - def setUp(self): - super(AuthenticateviaSAML2Tests, self).setUp() - - self.deprecations.expect_deprecations() - - self.conf_fixture = self.useFixture(config.Config()) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.session = session.Session() - - self.ECP_SP_EMPTY_REQUEST_HEADERS = { - 'Accept': 'text/html; application/vnd.paos+xml', - 'PAOS': ('ver="urn:liberty:paos:2003-08";' - '"urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp"') - } - - self.ECP_SP_SAML2_REQUEST_HEADERS = { - 'Content-Type': 'application/vnd.paos+xml' - } - - self.ECP_SAML2_NAMESPACES = { - 'ecp': 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp', - 'S': 'http://schemas.xmlsoap.org/soap/envelope/', - 'paos': 'urn:liberty:paos:2003-08' - } - self.ECP_RELAY_STATE = '//ecp:RelayState' - self.ECP_SERVICE_PROVIDER_CONSUMER_URL = ('/S:Envelope/S:Header/paos:' - 'Request/' - '@responseConsumerURL') - self.ECP_IDP_CONSUMER_URL = ('/S:Envelope/S:Header/ecp:Response/' - '@AssertionConsumerServiceURL') - self.IDENTITY_PROVIDER = 'testidp' - self.IDENTITY_PROVIDER_URL = 'http://local.url' - self.PROTOCOL = 'saml2' - self.FEDERATION_AUTH_URL = '%s/%s' % ( - self.TEST_URL, - 'OS-FEDERATION/identity_providers/testidp/protocols/saml2/auth') - self.SHIB_CONSUMER_URL = ('https://openstack4.local/' - 'Shibboleth.sso/SAML2/ECP') - - self.saml2plugin = saml2.Saml2UnscopedToken( - self.TEST_URL, - self.IDENTITY_PROVIDER, self.IDENTITY_PROVIDER_URL, - self.TEST_USER, self.TEST_TOKEN) - - def test_conf_params(self): - section = uuid.uuid4().hex - identity_provider = uuid.uuid4().hex - identity_provider_url = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(saml2.Saml2UnscopedToken.get_options(), - group=section) - self.conf_fixture.config(auth_plugin='v3unscopedsaml', - identity_provider=identity_provider, - identity_provider_url=identity_provider_url, - username=username, - password=password, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertEqual(identity_provider, a.identity_provider) - self.assertEqual(identity_provider_url, a.identity_provider_url) - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - - def test_initial_sp_call(self): - """Test initial call, expect SOAP message.""" - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - content=make_oneline(saml2_fixtures.SP_SOAP_RESPONSE)) - a = self.saml2plugin._send_service_provider_request(self.session) - - self.assertFalse(a) - - fixture_soap_response = make_oneline( - saml2_fixtures.SP_SOAP_RESPONSE) - - sp_soap_response = make_oneline( - etree.tostring(self.saml2plugin.saml2_authn_request)) - - error_msg = "Expected %s instead of %s" % (fixture_soap_response, - sp_soap_response) - - self.assertEqual(fixture_soap_response, sp_soap_response, error_msg) - - self.assertEqual( - self.saml2plugin.sp_response_consumer_url, self.SHIB_CONSUMER_URL, - "Expected consumer_url set to %s instead of %s" % ( - self.SHIB_CONSUMER_URL, - str(self.saml2plugin.sp_response_consumer_url))) - - def test_initial_sp_call_when_saml_authenticated(self): - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - a = self.saml2plugin._send_service_provider_request(self.session) - self.assertTrue(a) - self.assertEqual( - saml2_fixtures.UNSCOPED_TOKEN['token'], - self.saml2plugin.authenticated_response.json()['token']) - self.assertEqual( - saml2_fixtures.UNSCOPED_TOKEN_HEADER, - self.saml2plugin.authenticated_response.headers['X-Subject-Token']) - - def test_get_unscoped_token_when_authenticated(self): - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER, - 'Content-Type': 'application/json'}) - - token, token_body = self.saml2plugin._get_unscoped_token(self.session) - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], token_body) - - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, token) - - def test_initial_sp_call_invalid_response(self): - """Send initial SP HTTP request and receive wrong server response.""" - self.requests_mock.get(self.FEDERATION_AUTH_URL, - text='NON XML RESPONSE') - - self.assertRaises( - exceptions.AuthorizationFailure, - self.saml2plugin._send_service_provider_request, - self.session) - - def test_send_authn_req_to_idp(self): - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=saml2_fixtures.SAML2_ASSERTION) - - self.saml2plugin.sp_response_consumer_url = self.SHIB_CONSUMER_URL - self.saml2plugin.saml2_authn_request = etree.XML( - saml2_fixtures.SP_SOAP_RESPONSE) - self.saml2plugin._send_idp_saml2_authn_request(self.session) - - idp_response = make_oneline(etree.tostring( - self.saml2plugin.saml2_idp_authn_response)) - - saml2_assertion_oneline = make_oneline( - saml2_fixtures.SAML2_ASSERTION) - error = "Expected %s instead of %s" % (saml2_fixtures.SAML2_ASSERTION, - idp_response) - self.assertEqual(idp_response, saml2_assertion_oneline, error) - - def test_fail_basicauth_idp_authentication(self): - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, status_code=401) - - self.saml2plugin.sp_response_consumer_url = self.SHIB_CONSUMER_URL - self.saml2plugin.saml2_authn_request = etree.XML( - saml2_fixtures.SP_SOAP_RESPONSE) - self.assertRaises( - exceptions.Unauthorized, - self.saml2plugin._send_idp_saml2_authn_request, - self.session) - - def test_mising_username_password_in_plugin(self): - self.assertRaises(TypeError, - saml2.Saml2UnscopedToken, - self.TEST_URL, self.IDENTITY_PROVIDER, - self.IDENTITY_PROVIDER_URL) - - def test_send_authn_response_to_sp(self): - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - self.saml2plugin.relay_state = etree.XML( - saml2_fixtures.SP_SOAP_RESPONSE).xpath( - self.ECP_RELAY_STATE, namespaces=self.ECP_SAML2_NAMESPACES)[0] - - self.saml2plugin.saml2_idp_authn_response = etree.XML( - saml2_fixtures.SAML2_ASSERTION) - - self.saml2plugin.idp_response_consumer_url = self.SHIB_CONSUMER_URL - self.saml2plugin._send_service_provider_saml2_authn_response( - self.session) - token_json = self.saml2plugin.authenticated_response.json()['token'] - token = self.saml2plugin.authenticated_response.headers[ - 'X-Subject-Token'] - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], - token_json) - - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, - token) - - def test_consumer_url_mismatch_success(self): - self.saml2plugin._check_consumer_urls( - self.session, self.SHIB_CONSUMER_URL, - self.SHIB_CONSUMER_URL) - - def test_consumer_url_mismatch(self): - self.requests_mock.post(self.SHIB_CONSUMER_URL) - invalid_consumer_url = uuid.uuid4().hex - self.assertRaises( - exceptions.ValidationError, - self.saml2plugin._check_consumer_urls, - self.session, self.SHIB_CONSUMER_URL, - invalid_consumer_url) - - def test_custom_302_redirection(self): - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - text='BODY', - headers={'location': self.FEDERATION_AUTH_URL}, - status_code=302) - - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - self.session.redirect = False - response = self.session.post( - self.SHIB_CONSUMER_URL, data='CLIENT BODY') - self.assertEqual(302, response.status_code) - self.assertEqual(self.FEDERATION_AUTH_URL, - response.headers['location']) - - response = self.saml2plugin._handle_http_ecp_redirect( - self.session, response, 'GET') - - self.assertEqual(self.FEDERATION_AUTH_URL, response.request.url) - self.assertEqual('GET', response.request.method) - - def test_custom_303_redirection(self): - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - text='BODY', - headers={'location': self.FEDERATION_AUTH_URL}, - status_code=303) - - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - self.session.redirect = False - response = self.session.post( - self.SHIB_CONSUMER_URL, data='CLIENT BODY') - self.assertEqual(303, response.status_code) - self.assertEqual(self.FEDERATION_AUTH_URL, - response.headers['location']) - - response = self.saml2plugin._handle_http_ecp_redirect( - self.session, response, 'GET') - - self.assertEqual(self.FEDERATION_AUTH_URL, response.request.url) - self.assertEqual('GET', response.request.method) - - def test_end_to_end_workflow(self): - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - content=make_oneline(saml2_fixtures.SP_SOAP_RESPONSE)) - - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=saml2_fixtures.SAML2_ASSERTION) - - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER, - 'Content-Type': 'application/json'}) - - self.session.redirect = False - response = self.saml2plugin.get_auth_ref(self.session) - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, - response.auth_token) - - -class ScopeFederationTokenTests(AuthenticateviaSAML2Tests): - - TEST_TOKEN = client_fixtures.AUTH_SUBJECT_TOKEN - - def setUp(self): - super(ScopeFederationTokenTests, self).setUp() - - self.PROJECT_SCOPED_TOKEN_JSON = client_fixtures.project_scoped_token() - self.PROJECT_SCOPED_TOKEN_JSON['methods'] = ['saml2'] - - # for better readability - self.TEST_TENANT_ID = self.PROJECT_SCOPED_TOKEN_JSON.project_id - self.TEST_TENANT_NAME = self.PROJECT_SCOPED_TOKEN_JSON.project_name - - self.DOMAIN_SCOPED_TOKEN_JSON = client_fixtures.domain_scoped_token() - self.DOMAIN_SCOPED_TOKEN_JSON['methods'] = ['saml2'] - - # for better readability - self.TEST_DOMAIN_ID = self.DOMAIN_SCOPED_TOKEN_JSON.domain_id - self.TEST_DOMAIN_NAME = self.DOMAIN_SCOPED_TOKEN_JSON.domain_name - - self.saml2_scope_plugin = saml2.Saml2ScopedToken( - self.TEST_URL, saml2_fixtures.UNSCOPED_TOKEN_HEADER, - project_id=self.TEST_TENANT_ID) - - def test_scope_saml2_token_to_project(self): - self.stub_auth(json=self.PROJECT_SCOPED_TOKEN_JSON) - - token = self.saml2_scope_plugin.get_auth_ref(self.session) - self.assertTrue(token.project_scoped, "Received token is not scoped") - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token) - self.assertEqual(self.TEST_TENANT_ID, token.project_id) - self.assertEqual(self.TEST_TENANT_NAME, token.project_name) - - def test_scope_saml2_token_to_invalid_project(self): - self.stub_auth(status_code=401) - self.saml2_scope_plugin.project_id = uuid.uuid4().hex - self.saml2_scope_plugin.project_name = None - self.assertRaises(exceptions.Unauthorized, - self.saml2_scope_plugin.get_auth_ref, - self.session) - - def test_scope_saml2_token_to_invalid_domain(self): - self.stub_auth(status_code=401) - self.saml2_scope_plugin.project_id = None - self.saml2_scope_plugin.project_name = None - self.saml2_scope_plugin.domain_id = uuid.uuid4().hex - self.saml2_scope_plugin.domain_name = None - self.assertRaises(exceptions.Unauthorized, - self.saml2_scope_plugin.get_auth_ref, - self.session) - - def test_scope_saml2_token_to_domain(self): - self.stub_auth(json=self.DOMAIN_SCOPED_TOKEN_JSON) - token = self.saml2_scope_plugin.get_auth_ref(self.session) - self.assertTrue(token.domain_scoped, "Received token is not scoped") - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token) - self.assertEqual(self.TEST_DOMAIN_ID, token.domain_id) - self.assertEqual(self.TEST_DOMAIN_NAME, token.domain_name) - - def test_dont_set_project_nor_domain(self): - self.saml2_scope_plugin.project_id = None - self.saml2_scope_plugin.domain_id = None - self.assertRaises(exceptions.ValidationError, - saml2.Saml2ScopedToken, - self.TEST_URL, client_fixtures.AUTH_SUBJECT_TOKEN) - - -class AuthenticateviaADFSTests(utils.TestCase): - - GROUP = 'auth' - - NAMESPACES = { - 's': 'http://www.w3.org/2003/05/soap-envelope', - 'trust': 'http://docs.oasis-open.org/ws-sx/ws-trust/200512', - 'wsa': 'http://www.w3.org/2005/08/addressing', - 'wsp': 'http://schemas.xmlsoap.org/ws/2004/09/policy', - 'a': 'http://www.w3.org/2005/08/addressing', - 'o': ('http://docs.oasis-open.org/wss/2004/01/oasis' - '-200401-wss-wssecurity-secext-1.0.xsd') - } - - USER_XPATH = ('/s:Envelope/s:Header' - '/o:Security' - '/o:UsernameToken' - '/o:Username') - PASSWORD_XPATH = ('/s:Envelope/s:Header' - '/o:Security' - '/o:UsernameToken' - '/o:Password') - ADDRESS_XPATH = ('/s:Envelope/s:Body' - '/trust:RequestSecurityToken' - '/wsp:AppliesTo/wsa:EndpointReference' - '/wsa:Address') - TO_XPATH = ('/s:Envelope/s:Header' - '/a:To') - - @property - def _uuid4(self): - return '4b911420-4982-4009-8afc-5c596cd487f5' - - def setUp(self): - super(AuthenticateviaADFSTests, self).setUp() - - self.deprecations.expect_deprecations() - - self.conf_fixture = self.useFixture(config.Config()) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.session = session.Session(session=requests.Session()) - - self.IDENTITY_PROVIDER = 'adfs' - self.IDENTITY_PROVIDER_URL = ('http://adfs.local/adfs/service/trust/13' - '/usernamemixed') - self.FEDERATION_AUTH_URL = '%s/%s' % ( - self.TEST_URL, - 'OS-FEDERATION/identity_providers/adfs/protocols/saml2/auth') - self.SP_ENDPOINT = 'https://openstack4.local/Shibboleth.sso/ADFS' - - self.adfsplugin = saml2.ADFSUnscopedToken( - self.TEST_URL, self.IDENTITY_PROVIDER, - self.IDENTITY_PROVIDER_URL, self.SP_ENDPOINT, - self.TEST_USER, self.TEST_TOKEN) - - self.ADFS_SECURITY_TOKEN_RESPONSE = _load_xml( - 'ADFS_RequestSecurityTokenResponse.xml') - self.ADFS_FAULT = _load_xml('ADFS_fault.xml') - - def test_conf_params(self): - section = uuid.uuid4().hex - identity_provider = uuid.uuid4().hex - identity_provider_url = uuid.uuid4().hex - sp_endpoint = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(saml2.ADFSUnscopedToken.get_options(), - group=section) - self.conf_fixture.config(auth_plugin='v3unscopedadfs', - identity_provider=identity_provider, - identity_provider_url=identity_provider_url, - service_provider_endpoint=sp_endpoint, - username=username, - password=password, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertEqual(identity_provider, a.identity_provider) - self.assertEqual(identity_provider_url, a.identity_provider_url) - self.assertEqual(sp_endpoint, a.service_provider_endpoint) - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - - def test_get_adfs_security_token(self): - """Test ADFSUnscopedToken._get_adfs_security_token().""" - self.requests_mock.post( - self.IDENTITY_PROVIDER_URL, - content=make_oneline(self.ADFS_SECURITY_TOKEN_RESPONSE), - status_code=200) - - self.adfsplugin._prepare_adfs_request() - self.adfsplugin._get_adfs_security_token(self.session) - - adfs_response = etree.tostring(self.adfsplugin.adfs_token) - fixture_response = self.ADFS_SECURITY_TOKEN_RESPONSE - - self.assertEqual(fixture_response, adfs_response) - - def test_adfs_request_user(self): - self.adfsplugin._prepare_adfs_request() - user = self.adfsplugin.prepared_request.xpath( - self.USER_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.TEST_USER, user.text) - - def test_adfs_request_password(self): - self.adfsplugin._prepare_adfs_request() - password = self.adfsplugin.prepared_request.xpath( - self.PASSWORD_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.TEST_TOKEN, password.text) - - def test_adfs_request_to(self): - self.adfsplugin._prepare_adfs_request() - to = self.adfsplugin.prepared_request.xpath( - self.TO_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.IDENTITY_PROVIDER_URL, to.text) - - def test_prepare_adfs_request_address(self): - self.adfsplugin._prepare_adfs_request() - address = self.adfsplugin.prepared_request.xpath( - self.ADDRESS_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.SP_ENDPOINT, address.text) - - def test_prepare_sp_request(self): - assertion = etree.XML(self.ADFS_SECURITY_TOKEN_RESPONSE) - assertion = assertion.xpath( - saml2.ADFSUnscopedToken.ADFS_ASSERTION_XPATH, - namespaces=saml2.ADFSUnscopedToken.ADFS_TOKEN_NAMESPACES) - assertion = assertion[0] - assertion = etree.tostring(assertion) - - assertion = assertion.replace( - b'http://docs.oasis-open.org/ws-sx/ws-trust/200512', - b'http://schemas.xmlsoap.org/ws/2005/02/trust') - assertion = urllib.parse.quote(assertion) - assertion = 'wa=wsignin1.0&wresult=' + assertion - - self.adfsplugin.adfs_token = etree.XML( - self.ADFS_SECURITY_TOKEN_RESPONSE) - self.adfsplugin._prepare_sp_request() - - self.assertEqual(assertion, self.adfsplugin.encoded_assertion) - - def test_get_adfs_security_token_authn_fail(self): - """Test proper parsing XML fault after bad authentication. - - An exceptions.AuthorizationFailure should be raised including - error message from the XML message indicating where was the problem. - """ - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=make_oneline(self.ADFS_FAULT), - status_code=500) - - self.adfsplugin._prepare_adfs_request() - self.assertRaises(exceptions.AuthorizationFailure, - self.adfsplugin._get_adfs_security_token, - self.session) - # TODO(marek-denis): Python3 tests complain about missing 'message' - # attributes - # self.assertEqual('a:FailedAuthentication', e.message) - - def test_get_adfs_security_token_bad_response(self): - """Test proper handling HTTP 500 and mangled (non XML) response. - - This should never happen yet, keystoneclient should be prepared - and correctly raise exceptions.InternalServerError once it cannot - parse XML fault message - """ - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=b'NOT XML', - status_code=500) - self.adfsplugin._prepare_adfs_request() - self.assertRaises(exceptions.InternalServerError, - self.adfsplugin._get_adfs_security_token, - self.session) - - # TODO(marek-denis): Need to figure out how to properly send cookies - # from the request_uri() method. - def _send_assertion_to_service_provider(self): - """Test whether SP issues a cookie.""" - cookie = uuid.uuid4().hex - - self.requests_mock.post(self.SP_ENDPOINT, - headers={"set-cookie": cookie}, - status_code=302) - - self.adfsplugin.adfs_token = self._build_adfs_request() - self.adfsplugin._prepare_sp_request() - self.adfsplugin._send_assertion_to_service_provider(self.session) - - self.assertEqual(1, len(self.session.session.cookies)) - - def test_send_assertion_to_service_provider_bad_status(self): - self.requests_mock.post(self.SP_ENDPOINT, status_code=500) - - self.adfsplugin.adfs_token = etree.XML( - self.ADFS_SECURITY_TOKEN_RESPONSE) - self.adfsplugin._prepare_sp_request() - - self.assertRaises( - exceptions.InternalServerError, - self.adfsplugin._send_assertion_to_service_provider, - self.session) - - def test_access_sp_no_cookies_fail(self): - # There are no cookies in the session initially, and - # _access_service_provider requires a cookie in the session. - self.assertRaises(exceptions.AuthorizationFailure, - self.adfsplugin._access_service_provider, - self.session) - - def test_check_valid_token_when_authenticated(self): - self.requests_mock.get(self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers=client_fixtures.AUTH_RESPONSE_HEADERS) - - # _access_service_provider requires a cookie in the session. - cookie = requests.cookies.create_cookie( - name=self.getUniqueString(), value=self.getUniqueString()) - self.session.session.cookies.set_cookie(cookie) - - self.adfsplugin._access_service_provider(self.session) - response = self.adfsplugin.authenticated_response - - self.assertEqual(client_fixtures.AUTH_RESPONSE_HEADERS, - response.headers) - - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], - response.json()['token']) - - def test_end_to_end_workflow(self): - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=self.ADFS_SECURITY_TOKEN_RESPONSE, - status_code=200) - self.requests_mock.post(self.SP_ENDPOINT, - headers={"set-cookie": 'x'}, - status_code=302) - self.requests_mock.get(self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers=client_fixtures.AUTH_RESPONSE_HEADERS) - - # NOTE(marek-denis): We need to mimic this until self.requests_mock can - # issue cookies properly. - cookie = requests.cookies.create_cookie( - name=self.getUniqueString(), value=self.getUniqueString()) - self.session.session.cookies.set_cookie(cookie) - - token, token_json = self.adfsplugin._get_unscoped_token(self.session) - self.assertEqual(token, client_fixtures.AUTH_SUBJECT_TOKEN) - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], token_json) - - -class SAMLGenerationTests(utils.ClientTestCase): - - def setUp(self): - super(SAMLGenerationTests, self).setUp() - self.manager = self.client.federation.saml - self.SAML2_FULL_URL = ''.join([self.TEST_URL, - saml_manager.SAML2_ENDPOINT]) - self.ECP_FULL_URL = ''.join([self.TEST_URL, - saml_manager.ECP_ENDPOINT]) - - def test_saml_create(self): - """Test that a token can be exchanged for a SAML assertion.""" - token_id = uuid.uuid4().hex - service_provider_id = uuid.uuid4().hex - - # Mock the returned text for '/auth/OS-FEDERATION/saml2 - self.requests_mock.post(self.SAML2_FULL_URL, - text=saml2_fixtures.TOKEN_BASED_SAML) - - text = self.manager.create_saml_assertion(service_provider_id, - token_id) - - # Ensure returned text is correct - self.assertEqual(saml2_fixtures.TOKEN_BASED_SAML, text) - - # Ensure request headers and body are correct - req_json = self.requests_mock.last_request.json() - self.assertEqual(token_id, req_json['auth']['identity']['token']['id']) - self.assertEqual(service_provider_id, - req_json['auth']['scope']['service_provider']['id']) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - - def test_ecp_create(self): - """Test that a token can be exchanged for an ECP wrapped assertion.""" - token_id = uuid.uuid4().hex - service_provider_id = uuid.uuid4().hex - - # Mock returned text for '/auth/OS-FEDERATION/saml2/ecp - self.requests_mock.post(self.ECP_FULL_URL, - text=saml2_fixtures.TOKEN_BASED_ECP) - - text = self.manager.create_ecp_assertion(service_provider_id, - token_id) - - # Ensure returned text is correct - self.assertEqual(saml2_fixtures.TOKEN_BASED_ECP, text) - - # Ensure request headers and body are correct - req_json = self.requests_mock.last_request.json() - self.assertEqual(token_id, req_json['auth']['identity']['token']['id']) - self.assertEqual(service_provider_id, - req_json['auth']['scope']['service_provider']['id']) - self.assertRequestHeaderEqual('Content-Type', 'application/json') diff --git a/keystoneclient/tests/unit/v3/test_client.py b/keystoneclient/tests/unit/v3/test_client.py deleted file mode 100644 index feb921a5..00000000 --- a/keystoneclient/tests/unit/v3/test_client.py +++ /dev/null @@ -1,270 +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. - -import copy -import json -import uuid - - -from keystoneauth1 import session as auth_session -from keystoneclient.auth import token_endpoint -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import client - - -class KeystoneClientTest(utils.TestCase): - - def test_unscoped_init(self): - token = client_fixtures.unscoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_domain_name=token.user_domain_name, - username=token.user_name, - password='password', - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - self.assertFalse(c.has_service_catalog()) - - self.assertEqual(token.user_id, c.get_user_id(session=None)) - self.assertIsNone(c.get_project_id(session=None)) - - def test_domain_scoped_init(self): - token = client_fixtures.domain_scoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=token.user_id, - password='password', - domain_name=token.domain_name, - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - self.assertTrue(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - self.assertEqual(token.domain_id, c.auth_domain_id) - - def test_project_scoped_init(self): - token = client_fixtures.project_scoped_token() - self.stub_auth(json=token), - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=token.user_id, - password='password', - user_domain_name=token.user_domain_name, - project_name=token.project_name, - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertTrue(c.auth_ref.project_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - self.assertEqual(token.project_id, c.auth_tenant_id) - self.assertEqual(token.user_id, c.get_user_id(session=None)) - self.assertEqual(token.project_id, c.get_project_id(session=None)) - - def test_auth_ref_load(self): - token = client_fixtures.project_scoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=token.user_id, - password='password', - project_id=token.project_id, - auth_url=self.TEST_URL) - cache = json.dumps(c.auth_ref) - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache)) - self.assertIsNotNone(new_client.auth_ref) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertEqual(token.user_name, new_client.username) - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v3') - - def test_auth_ref_load_with_overridden_arguments(self): - new_auth_url = 'https://newkeystone.com/v3' - - user_id = uuid.uuid4().hex - user_name = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - first = client_fixtures.project_scoped_token(user_id=user_id, - user_name=user_name, - project_id=project_id) - second = client_fixtures.project_scoped_token(user_id=user_id, - user_name=user_name, - project_id=project_id) - self.stub_auth(json=first) - self.stub_auth(json=second, base_url=new_auth_url) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=user_id, - password='password', - project_id=project_id, - auth_url=self.TEST_URL) - cache = json.dumps(c.auth_ref) - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache), - auth_url=new_auth_url) - self.assertIsNotNone(new_client.auth_ref) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertEqual(new_auth_url, new_client.auth_url) - self.assertEqual(user_name, new_client.username) - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v3') - - def test_trust_init(self): - token = client_fixtures.trust_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_domain_name=token.user_domain_name, - username=token.user_name, - password='password', - auth_url=self.TEST_URL, - trust_id=token.trust_id) - self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(token.trust_id, c.auth_ref.trust_id) - self.assertEqual(token.trustee_user_id, c.auth_ref.trustee_user_id) - self.assertEqual(token.trustor_user_id, c.auth_ref.trustor_user_id) - self.assertTrue(c.auth_ref.trust_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - - def test_init_err_no_auth_url(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - username='exampleuser', - password='password') - - def _management_url_is_updated(self, fixture, **kwargs): - second = copy.deepcopy(fixture) - first_url = 'http://admin:35357/v3' - second_url = "http://secondurl:%d/v3'" - - for entry in second['token']['catalog']: - if entry['type'] == 'identity': - entry['endpoints'] = [{ - 'url': second_url % 5000, - 'region': 'RegionOne', - 'interface': 'public' - }, { - 'url': second_url % 5000, - 'region': 'RegionOne', - 'interface': 'internal' - }, { - 'url': second_url % 35357, - 'region': 'RegionOne', - 'interface': 'admin' - }] - - self.stub_auth(response_list=[{'json': fixture}, {'json': second}]) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - auth_url=self.TEST_URL, - **kwargs) - self.assertEqual(cl.management_url, first_url) - - with self.deprecations.expect_deprecations_here(): - cl.authenticate() - self.assertEqual(cl.management_url, second_url % 35357) - - def test_management_url_is_updated_with_project(self): - self._management_url_is_updated(client_fixtures.project_scoped_token(), - project_name='exampleproject') - - def test_management_url_is_updated_with_domain(self): - self._management_url_is_updated(client_fixtures.domain_scoped_token(), - domain_name='exampledomain') - - def test_client_with_region_name_passes_to_service_catalog(self): - # NOTE(jamielennox): this is deprecated behaviour that should be - # removed ASAP, however must remain compatible. - self.deprecations.expect_deprecations() - - self.stub_auth(json=client_fixtures.auth_response_body()) - - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='North') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'http://glance.north.host/glanceapi/public') - - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='South') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'http://glance.south.host/glanceapi/public') - - def test_client_without_auth_params(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - project_name='exampleproject', - auth_url=self.TEST_URL) - - def test_client_params(self): - with self.deprecations.expect_deprecations_here(): - sess = session.Session() - auth = token_endpoint.Token('a', 'b') - - opts = {'auth': auth, - 'connect_retries': 50, - 'endpoint_override': uuid.uuid4().hex, - 'interface': uuid.uuid4().hex, - 'region_name': uuid.uuid4().hex, - 'service_name': uuid.uuid4().hex, - 'user_agent': uuid.uuid4().hex, - } - - cl = client.Client(session=sess, **opts) - - for k, v in opts.items(): - self.assertEqual(v, getattr(cl._adapter, k)) - - self.assertEqual('identity', cl._adapter.service_type) - self.assertEqual((3, 0), cl._adapter.version) - - def test_empty_service_catalog_param(self): - # Client().service_catalog should return None if the client is not - # authenticated - sess = auth_session.Session() - cl = client.Client(session=sess) - self.assertIsNone(cl.service_catalog) diff --git a/keystoneclient/tests/unit/v3/test_credentials.py b/keystoneclient/tests/unit/v3/test_credentials.py deleted file mode 100644 index 0efc3dfb..00000000 --- a/keystoneclient/tests/unit/v3/test_credentials.py +++ /dev/null @@ -1,33 +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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import credentials - - -class CredentialTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(CredentialTests, self).setUp() - self.key = 'credential' - self.collection_key = 'credentials' - self.model = credentials.Credential - self.manager = self.client.credentials - - def new_ref(self, **kwargs): - kwargs = super(CredentialTests, self).new_ref(**kwargs) - kwargs.setdefault('blob', uuid.uuid4().hex) - kwargs.setdefault('project_id', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('user_id', uuid.uuid4().hex) - return kwargs diff --git a/keystoneclient/tests/unit/v3/test_discover.py b/keystoneclient/tests/unit/v3/test_discover.py deleted file mode 100644 index f54b2f9c..00000000 --- a/keystoneclient/tests/unit/v3/test_discover.py +++ /dev/null @@ -1,82 +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.generic import client -from keystoneclient.tests.unit.v3 import utils - - -class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): - def setUp(self): - super(DiscoverKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "versions": { - "values": [{"id": "v3.0", - "status": "beta", - "updated": "2013-03-06T00:00:00Z", - "links": [ - {"rel": "self", - "href": "http://127.0.0.1:5000/v3.0/", }, - {"rel": "describedby", - "type": "text/html", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/3/" - "content/", }, - {"rel": "describedby", - "type": "application/pdf", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/3/" - "identity-dev-guide-3.pdf", }, - ]}, - {"id": "v2.0", - "status": "beta", - "updated": "2013-03-06T00:00:00Z", - "links": [ - {"rel": "self", - "href": "http://127.0.0.1:5000/v2.0/", }, - {"rel": "describedby", - "type": "text/html", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/" - "content/", }, - {"rel": "describedby", - "type": "application/pdf", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/" - "identity-dev-guide-2.0.pdf", } - ]}], - }, - } - self.TEST_REQUEST_HEADERS = { - 'User-Agent': 'python-keystoneclient', - 'Accept': 'application/json', - } - - def test_get_version_local(self): - self.requests_mock.get("http://localhost:35357/", - status_code=300, - json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client() - versions = cs.discover() - self.assertIsInstance(versions, dict) - self.assertIn('message', versions) - self.assertIn('v3.0', versions) - self.assertEqual( - versions['v3.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][0]['links'][0] - ['href']) - self.assertEqual( - versions['v2.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][1]['links'][0] - ['href']) diff --git a/keystoneclient/tests/unit/v3/test_domain_configs.py b/keystoneclient/tests/unit/v3/test_domain_configs.py deleted file mode 100644 index 2a7df092..00000000 --- a/keystoneclient/tests/unit/v3/test_domain_configs.py +++ /dev/null @@ -1,96 +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. - -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import domain_configs - - -class DomainConfigsTests(utils.ClientTestCase, utils.CrudTests): - """Test domain config database management.""" - - def setUp(self): - super(DomainConfigsTests, self).setUp() - self.key = 'config' - self.model = domain_configs.DomainConfig - self.manager = self.client.domain_configs - - def new_ref(self, **kwargs): - config_groups = {'identity': {uuid.uuid4().hex: uuid.uuid4().hex}, - 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}} - kwargs.setdefault('config', config_groups) - return kwargs - - def _assert_resource_attributes(self, resource, req_ref): - for attr in req_ref: - self.assertEqual( - getattr(resource, attr), - req_ref[attr], - 'Expected different %s' % attr) - - def test_create(self): - domain_id = uuid.uuid4().hex - config = self.new_ref() - - self.stub_url('PUT', - parts=['domains', domain_id, 'config'], - json=config, status_code=201) - res = self.manager.create(domain_id, config) - self._assert_resource_attributes(res, config['config']) - self.assertEntityRequestBodyIs(config) - - def test_update(self): - domain_id = uuid.uuid4().hex - config = self.new_ref() - - self.stub_url('PATCH', - parts=['domains', domain_id, 'config'], - json=config, status_code=200) - res = self.manager.update(domain_id, config) - self._assert_resource_attributes(res, config['config']) - self.assertEntityRequestBodyIs(config) - - def test_get(self): - domain_id = uuid.uuid4().hex - config = self.new_ref() - config = config['config'] - - self.stub_entity('GET', - parts=['domains', domain_id, 'config'], - entity=config) - res = self.manager.get(domain_id) - self._assert_resource_attributes(res, config) - - def test_delete(self): - domain_id = uuid.uuid4().hex - self.stub_url('DELETE', - parts=['domains', domain_id, 'config'], - status_code=204) - self.manager.delete(domain_id) - - def test_list(self): - # List not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.list) - - def test_list_by_id(self): - # List not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.list) - - def test_list_params(self): - # List not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.list) - - def test_find(self): - # Find not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.find) diff --git a/keystoneclient/tests/unit/v3/test_domains.py b/keystoneclient/tests/unit/v3/test_domains.py deleted file mode 100644 index 72a7b883..00000000 --- a/keystoneclient/tests/unit/v3/test_domains.py +++ /dev/null @@ -1,53 +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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import domains - - -class DomainTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(DomainTests, self).setUp() - self.key = 'domain' - self.collection_key = 'domains' - self.model = domains.Domain - self.manager = self.client.domains - - def new_ref(self, **kwargs): - kwargs = super(DomainTests, self).new_ref(**kwargs) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_filter_for_default_domain_by_id(self): - ref = self.new_ref(id='default') - super(DomainTests, self).test_list_by_id( - ref=ref, - id=ref['id']) - - def test_list_filter_name(self): - super(DomainTests, self).test_list(name='adomain123') - - def test_list_filter_enabled(self): - super(DomainTests, self).test_list(enabled=True) - - def test_list_filter_disabled(self): - # False is converted to '0' ref bug #1267530 - expected_query = {'enabled': '0'} - super(DomainTests, self).test_list(expected_query=expected_query, - enabled=False) - - def test_update_enabled_defaults_to_none(self): - super(DomainTests, self).test_update( - req_ref={'name': uuid.uuid4().hex}) diff --git a/keystoneclient/tests/unit/v3/test_ec2.py b/keystoneclient/tests/unit/v3/test_ec2.py deleted file mode 100644 index 66679f60..00000000 --- a/keystoneclient/tests/unit/v3/test_ec2.py +++ /dev/null @@ -1,107 +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.tests.unit.v3 import utils -from keystoneclient.v3 import ec2 - - -class EC2Tests(utils.ClientTestCase): - - def test_create(self): - user_id = 'usr' - tenant_id = 'tnt' - req_body = { - "tenant_id": tenant_id, - } - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('POST', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - cred = self.client.ec2.create(user_id, tenant_id) - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - self.assertRequestBodyIs(json=req_body) - - def test_get(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2', 'access'], json=resp_body) - - cred = self.client.ec2.get(user_id, 'access') - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_list(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credentials": { - "values": [ - { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - }, - { - "access": "another", - "secret": "key", - "tenant_id": tenant_id, - "created": "12/12/31", - "enabled": True, - } - ] - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - creds = self.client.ec2.list(user_id) - self.assertEqual(len(creds), 2) - cred = creds[0] - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_delete(self): - user_id = 'usr' - access = 'access' - self.stub_url('DELETE', ['users', user_id, 'credentials', - 'OS-EC2', access], status_code=204) - self.client.ec2.delete(user_id, access) diff --git a/keystoneclient/tests/unit/v3/test_endpoint_filter.py b/keystoneclient/tests/unit/v3/test_endpoint_filter.py deleted file mode 100644 index 62e89cb3..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoint_filter.py +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright 2014 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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils - - -class EndpointTestUtils(object): - """Mixin class with shared methods between Endpoint Filter & Policy.""" - - def new_ref(self, **kwargs): - # copied from CrudTests as we need to create endpoint and project - # refs for our tests. EndpointFilter is not exactly CRUD API. - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def new_endpoint_ref(self, **kwargs): - # copied from EndpointTests as we need endpoint refs for our tests - kwargs = self.new_ref(**kwargs) - kwargs.setdefault('interface', 'public') - kwargs.setdefault('region', uuid.uuid4().hex) - kwargs.setdefault('service_id', uuid.uuid4().hex) - kwargs.setdefault('url', uuid.uuid4().hex) - return kwargs - - def new_endpoint_group_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('filters') - return kwargs - - -class EndpointFilterTests(utils.ClientTestCase, EndpointTestUtils): - """Test project-endpoint associations (a.k.a. EndpointFilter Extension). - - Endpoint filter provides associations between service endpoints and - projects. These assciations are then used to create ad-hoc catalogs for - each project-scoped token request. - - """ - - def setUp(self): - super(EndpointFilterTests, self).setUp() - self.manager = self.client.endpoint_filter - - def new_project_ref(self, **kwargs): - # copied from ProjectTests as we need project refs for our tests - kwargs = self.new_ref(**kwargs) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_add_endpoint_to_project_via_id(self): - endpoint_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('PUT', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints', endpoint_id], - status_code=201) - - self.manager.add_endpoint_to_project(project=project_id, - endpoint=endpoint_id) - - def test_add_endpoint_to_project_via_obj(self): - project_ref = self.new_project_ref() - endpoint_ref = self.new_endpoint_ref() - project = self.client.projects.resource_class(self.client.projects, - project_ref, - loaded=True) - endpoint = self.client.endpoints.resource_class(self.client.endpoints, - endpoint_ref, - loaded=True) - - self.stub_url('PUT', - [self.manager.OS_EP_FILTER_EXT, - 'projects', project_ref['id'], - 'endpoints', endpoint_ref['id']], - status_code=201) - - self.manager.add_endpoint_to_project(project=project, - endpoint=endpoint) - - def test_delete_endpoint_from_project(self): - endpoint_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('DELETE', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints', endpoint_id], - status_code=201) - - self.manager.delete_endpoint_from_project(project=project_id, - endpoint=endpoint_id) - - def test_check_endpoint_in_project(self): - endpoint_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('HEAD', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints', endpoint_id], - status_code=201) - - self.manager.check_endpoint_in_project(project=project_id, - endpoint=endpoint_id) - - def test_list_endpoints_for_project(self): - project_id = uuid.uuid4().hex - endpoints = {'endpoints': [self.new_endpoint_ref(), - self.new_endpoint_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints'], - json=endpoints, - status_code=200) - - endpoints_resp = self.manager.list_endpoints_for_project( - project=project_id) - - expected_endpoint_ids = [ - endpoint['id'] for endpoint in endpoints['endpoints']] - actual_endpoint_ids = [endpoint.id for endpoint in endpoints_resp] - self.assertEqual(expected_endpoint_ids, actual_endpoint_ids) - - def test_list_projects_for_endpoint(self): - endpoint_id = uuid.uuid4().hex - projects = {'projects': [self.new_project_ref(), - self.new_project_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'endpoints', endpoint_id, - 'projects'], - json=projects, - status_code=200) - - projects_resp = self.manager.list_projects_for_endpoint( - endpoint=endpoint_id) - - expected_project_ids = [ - project['id'] for project in projects['projects']] - actual_project_ids = [project.id for project in projects_resp] - self.assertEqual(expected_project_ids, actual_project_ids) - - def test_list_projects_for_endpoint_group(self): - endpoint_group_id = uuid.uuid4().hex - projects = {'projects': [self.new_project_ref(), - self.new_project_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects'], - json=projects, - status_code=200) - - projects_resp = self.manager.list_projects_for_endpoint_group( - endpoint_group=endpoint_group_id) - - expected_project_ids = [ - project['id'] for project in projects['projects']] - actual_project_ids = [project.id for project in projects_resp] - self.assertEqual(expected_project_ids, actual_project_ids) - - def test_list_projects_for_endpoint_group_value_error(self): - self.assertRaises(ValueError, - self.manager.list_projects_for_endpoint_group, - endpoint_group='') - self.assertRaises(ValueError, - self.manager.list_projects_for_endpoint_group, - endpoint_group=None) - - def test_list_endpoint_groups_for_project(self): - project_id = uuid.uuid4().hex - endpoint_groups = { - 'endpoint_groups': [self.new_endpoint_group_ref(), - self.new_endpoint_group_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'projects', - project_id, 'endpoint_groups'], - json=endpoint_groups, - status_code=200) - - endpoint_groups_resp = self.manager.list_endpoint_groups_for_project( - project=project_id) - - expected_endpoint_group_ids = [ - endpoint_group['id'] for endpoint_group - in endpoint_groups['endpoint_groups'] - ] - actual_endpoint_group_ids = [ - endpoint_group.id for endpoint_group in endpoint_groups_resp - ] - self.assertEqual(expected_endpoint_group_ids, - actual_endpoint_group_ids) - - def test_list_endpoint_groups_for_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.list_endpoint_groups_for_project, - project=value) - - def test_add_endpoint_group_to_project(self): - endpoint_group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('PUT', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects', project_id], - status_code=201) - - self.manager.add_endpoint_group_to_project( - project=project_id, endpoint_group=endpoint_group_id) - - def test_add_endpoint_group_to_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.add_endpoint_group_to_project, - project=value, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.add_endpoint_group_to_project, - project=uuid.uuid4().hex, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.add_endpoint_group_to_project, - project=value, - endpoint_group=uuid.uuid4().hex) - - def test_check_endpoint_group_in_project(self): - endpoint_group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('HEAD', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects', project_id], - status_code=201) - - self.manager.check_endpoint_group_in_project( - project=project_id, endpoint_group=endpoint_group_id) - - def test_check_endpoint_group_in_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.check_endpoint_group_in_project, - project=value, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.check_endpoint_group_in_project, - project=uuid.uuid4().hex, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.check_endpoint_group_in_project, - project=value, - endpoint_group=uuid.uuid4().hex) - - def test_delete_endpoint_group_from_project(self): - endpoint_group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('DELETE', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects', project_id], - status_code=201) - - self.manager.delete_endpoint_group_from_project( - project=project_id, endpoint_group=endpoint_group_id) - - def test_delete_endpoint_group_from_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.delete_endpoint_group_from_project, - project=value, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.delete_endpoint_group_from_project, - project=uuid.uuid4().hex, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.delete_endpoint_group_from_project, - project=value, - endpoint_group=uuid.uuid4().hex) diff --git a/keystoneclient/tests/unit/v3/test_endpoint_groups.py b/keystoneclient/tests/unit/v3/test_endpoint_groups.py deleted file mode 100644 index 364fd53c..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoint_groups.py +++ /dev/null @@ -1,34 +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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import endpoint_groups - - -class EndpointGroupTests(utils.ClientTestCase, utils.CrudTests): - - def setUp(self): - super(EndpointGroupTests, self).setUp() - self.key = 'endpoint_group' - self.collection_key = 'endpoint_groups' - self.model = endpoint_groups.EndpointGroup - self.manager = self.client.endpoint_groups - self.path_prefix = 'OS-EP-FILTER' - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('filters', '{"interface": "public"}') - kwargs.setdefault('description', uuid.uuid4().hex) - return kwargs diff --git a/keystoneclient/tests/unit/v3/test_endpoint_policy.py b/keystoneclient/tests/unit/v3/test_endpoint_policy.py deleted file mode 100644 index 69d90ae5..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoint_policy.py +++ /dev/null @@ -1,242 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import test_endpoint_filter -from keystoneclient.tests.unit.v3 import utils - - -class EndpointPolicyTests(utils.ClientTestCase, - test_endpoint_filter.EndpointTestUtils): - """Test policy-endpoint associations (a.k.a. EndpointPolicy Extension).""" - - def setUp(self): - super(EndpointPolicyTests, self).setUp() - self.manager = self.client.endpoint_policy - - def new_policy_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('blob', uuid.uuid4().hex) - return kwargs - - def new_region_ref(self, **kwargs): - kwargs = self.new_ref(**kwargs) - return kwargs - - def new_service_ref(self, **kwargs): - kwargs = self.new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - return kwargs - - def _crud_policy_association_for_endpoint_via_id( - self, http_action, manager_action): - policy_id = uuid.uuid4().hex - endpoint_id = uuid.uuid4().hex - - self.stub_url(http_action, - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'endpoints', endpoint_id], - status_code=204) - manager_action(policy=policy_id, endpoint=endpoint_id) - - def _crud_policy_association_for_endpoint_via_obj( - self, http_action, manager_action): - policy_ref = self.new_policy_ref() - endpoint_ref = self.new_endpoint_ref() - policy = self.client.policies.resource_class( - self.client.policies, policy_ref, loaded=True) - endpoint = self.client.endpoints.resource_class( - self.client.endpoints, endpoint_ref, loaded=True) - - self.stub_url(http_action, - ['policies', policy_ref['id'], - self.manager.OS_EP_POLICY_EXT, - 'endpoints', endpoint_ref['id']], - status_code=204) - manager_action(policy=policy, endpoint=endpoint) - - def test_create_policy_association_for_endpoint_via_id(self): - self._crud_policy_association_for_endpoint_via_id( - 'PUT', self.manager.create_policy_association_for_endpoint) - - def test_create_policy_association_for_endpoint_via_obj(self): - self._crud_policy_association_for_endpoint_via_obj( - 'PUT', self.manager.create_policy_association_for_endpoint) - - def test_check_policy_association_for_endpoint_via_id(self): - self._crud_policy_association_for_endpoint_via_id( - 'HEAD', self.manager.check_policy_association_for_endpoint) - - def test_check_policy_association_for_endpoint_via_obj(self): - self._crud_policy_association_for_endpoint_via_obj( - 'HEAD', self.manager.check_policy_association_for_endpoint) - - def test_delete_policy_association_for_endpoint_via_id(self): - self._crud_policy_association_for_endpoint_via_id( - 'DELETE', self.manager.delete_policy_association_for_endpoint) - - def test_delete_policy_association_for_endpoint_via_obj(self): - self._crud_policy_association_for_endpoint_via_obj( - 'DELETE', self.manager.delete_policy_association_for_endpoint) - - def _crud_policy_association_for_service_via_id( - self, http_action, manager_action): - policy_id = uuid.uuid4().hex - service_id = uuid.uuid4().hex - - self.stub_url(http_action, - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'services', service_id], - status_code=204) - manager_action(policy=policy_id, service=service_id) - - def _crud_policy_association_for_service_via_obj( - self, http_action, manager_action): - policy_ref = self.new_policy_ref() - service_ref = self.new_service_ref() - policy = self.client.policies.resource_class( - self.client.policies, policy_ref, loaded=True) - service = self.client.services.resource_class( - self.client.services, service_ref, loaded=True) - - self.stub_url(http_action, - ['policies', policy_ref['id'], - self.manager.OS_EP_POLICY_EXT, - 'services', service_ref['id']], - status_code=204) - manager_action(policy=policy, service=service) - - def test_create_policy_association_for_service_via_id(self): - self._crud_policy_association_for_service_via_id( - 'PUT', self.manager.create_policy_association_for_service) - - def test_create_policy_association_for_service_via_obj(self): - self._crud_policy_association_for_service_via_obj( - 'PUT', self.manager.create_policy_association_for_service) - - def test_check_policy_association_for_service_via_id(self): - self._crud_policy_association_for_service_via_id( - 'HEAD', self.manager.check_policy_association_for_service) - - def test_check_policy_association_for_service_via_obj(self): - self._crud_policy_association_for_service_via_obj( - 'HEAD', self.manager.check_policy_association_for_service) - - def test_delete_policy_association_for_service_via_id(self): - self._crud_policy_association_for_service_via_id( - 'DELETE', self.manager.delete_policy_association_for_service) - - def test_delete_policy_association_for_service_via_obj(self): - self._crud_policy_association_for_service_via_obj( - 'DELETE', self.manager.delete_policy_association_for_service) - - def _crud_policy_association_for_region_and_service_via_id( - self, http_action, manager_action): - policy_id = uuid.uuid4().hex - region_id = uuid.uuid4().hex - service_id = uuid.uuid4().hex - - self.stub_url(http_action, - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'services', service_id, 'regions', region_id], - status_code=204) - manager_action(policy=policy_id, region=region_id, service=service_id) - - def _crud_policy_association_for_region_and_service_via_obj( - self, http_action, manager_action): - policy_ref = self.new_policy_ref() - region_ref = self.new_region_ref() - service_ref = self.new_service_ref() - policy = self.client.policies.resource_class( - self.client.policies, policy_ref, loaded=True) - region = self.client.regions.resource_class( - self.client.regions, region_ref, loaded=True) - service = self.client.services.resource_class( - self.client.services, service_ref, loaded=True) - - self.stub_url(http_action, - ['policies', policy_ref['id'], - self.manager.OS_EP_POLICY_EXT, - 'services', service_ref['id'], - 'regions', region_ref['id']], - status_code=204) - manager_action(policy=policy, region=region, service=service) - - def test_create_policy_association_for_region_and_service_via_id(self): - self._crud_policy_association_for_region_and_service_via_id( - 'PUT', - self.manager.create_policy_association_for_region_and_service) - - def test_create_policy_association_for_region_and_service_via_obj(self): - self._crud_policy_association_for_region_and_service_via_obj( - 'PUT', - self.manager.create_policy_association_for_region_and_service) - - def test_check_policy_association_for_region_and_service_via_id(self): - self._crud_policy_association_for_region_and_service_via_id( - 'HEAD', - self.manager.check_policy_association_for_region_and_service) - - def test_check_policy_association_for_region_and_service_via_obj(self): - self._crud_policy_association_for_region_and_service_via_obj( - 'HEAD', - self.manager.check_policy_association_for_region_and_service) - - def test_delete_policy_association_for_region_and_service_via_id(self): - self._crud_policy_association_for_region_and_service_via_id( - 'DELETE', - self.manager.delete_policy_association_for_region_and_service) - - def test_delete_policy_association_for_region_and_service_via_obj(self): - self._crud_policy_association_for_region_and_service_via_obj( - 'DELETE', - self.manager.delete_policy_association_for_region_and_service) - - def test_get_policy_for_endpoint(self): - endpoint_id = uuid.uuid4().hex - expected_policy = self.new_policy_ref() - - self.stub_url('GET', - ['endpoints', endpoint_id, self.manager.OS_EP_POLICY_EXT, - 'policy'], - json={'policy': expected_policy}, - status_code=200) - - policy_resp = self.manager.get_policy_for_endpoint( - endpoint=endpoint_id) - - self.assertEqual(expected_policy['id'], policy_resp.id) - self.assertEqual(expected_policy['blob'], policy_resp.blob) - self.assertEqual(expected_policy['type'], policy_resp.type) - - def test_list_endpoints_for_policy(self): - policy_id = uuid.uuid4().hex - endpoints = {'endpoints': [self.new_endpoint_ref(), - self.new_endpoint_ref()]} - self.stub_url('GET', - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'endpoints'], - json=endpoints, - status_code=200) - - endpoints_resp = self.manager.list_endpoints_for_policy( - policy=policy_id) - - expected_endpoint_ids = [ - endpoint['id'] for endpoint in endpoints['endpoints']] - actual_endpoint_ids = [endpoint.id for endpoint in endpoints_resp] - self.assertEqual(expected_endpoint_ids, actual_endpoint_ids) diff --git a/keystoneclient/tests/unit/v3/test_endpoints.py b/keystoneclient/tests/unit/v3/test_endpoints.py deleted file mode 100644 index 40fc03be..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoints.py +++ /dev/null @@ -1,104 +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. - -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import endpoints - - -class EndpointTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(EndpointTests, self).setUp() - self.key = 'endpoint' - self.collection_key = 'endpoints' - self.model = endpoints.Endpoint - self.manager = self.client.endpoints - - def new_ref(self, **kwargs): - kwargs = super(EndpointTests, self).new_ref(**kwargs) - kwargs.setdefault('interface', 'public') - kwargs.setdefault('region', uuid.uuid4().hex) - kwargs.setdefault('service_id', uuid.uuid4().hex) - kwargs.setdefault('url', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def test_create_public_interface(self): - ref = self.new_ref(interface='public') - self.test_create(ref) - - def test_create_admin_interface(self): - ref = self.new_ref(interface='admin') - self.test_create(ref) - - def test_create_internal_interface(self): - ref = self.new_ref(interface='internal') - self.test_create(ref) - - def test_create_invalid_interface(self): - ref = self.new_ref(interface=uuid.uuid4().hex) - self.assertRaises(exceptions.ValidationError, self.manager.create, - **utils.parameterize(ref)) - - def test_update_public_interface(self): - ref = self.new_ref(interface='public') - self.test_update(ref) - - def test_update_admin_interface(self): - ref = self.new_ref(interface='admin') - self.test_update(ref) - - def test_update_internal_interface(self): - ref = self.new_ref(interface='internal') - self.test_update(ref) - - def test_update_invalid_interface(self): - ref = self.new_ref(interface=uuid.uuid4().hex) - ref['endpoint'] = "fake_endpoint" - self.assertRaises(exceptions.ValidationError, self.manager.update, - **utils.parameterize(ref)) - - def test_list_public_interface(self): - interface = 'public' - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.test_list(expected_path=expected_path, interface=interface) - - def test_list_admin_interface(self): - interface = 'admin' - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.test_list(expected_path=expected_path, interface=interface) - - def test_list_internal_interface(self): - interface = 'admin' - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.test_list(expected_path=expected_path, interface=interface) - - def test_list_invalid_interface(self): - interface = uuid.uuid4().hex - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.assertRaises(exceptions.ValidationError, self.manager.list, - expected_path=expected_path, interface=interface) - - def test_list_filtered_by_region(self): - region_id = uuid.uuid4().hex - ref_list = [self.new_ref(region=region_id), - self.new_ref(region=region_id)] - expected_path = 'v3/%s?region_id=%s' % (self.collection_key, region_id) - expected_query = {'region_id': region_id} - - # Validate passing either region or region_id result to the API call. - self.test_list(ref_list=ref_list, expected_path=expected_path, - expected_query=expected_query, region=region_id) - self.test_list(ref_list=ref_list, expected_path=expected_path, - expected_query=expected_query, region_id=region_id) diff --git a/keystoneclient/tests/unit/v3/test_federation.py b/keystoneclient/tests/unit/v3/test_federation.py deleted file mode 100644 index a760ed7d..00000000 --- a/keystoneclient/tests/unit/v3/test_federation.py +++ /dev/null @@ -1,584 +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. - -import copy -import uuid - -from keystoneauth1 import exceptions -from keystoneauth1 import fixture -from keystoneauth1.identity import v3 -from keystoneauth1 import session -from keystoneauth1.tests.unit import k2k_fixtures -import six -from testtools import matchers - -from keystoneclient import access -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import client -from keystoneclient.v3.contrib.federation import base -from keystoneclient.v3.contrib.federation import identity_providers -from keystoneclient.v3.contrib.federation import mappings -from keystoneclient.v3.contrib.federation import protocols -from keystoneclient.v3.contrib.federation import service_providers -from keystoneclient.v3 import domains -from keystoneclient.v3 import projects - - -class IdentityProviderTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(IdentityProviderTests, self).setUp() - self.key = 'identity_provider' - self.collection_key = 'identity_providers' - self.model = identity_providers.IdentityProvider - self.manager = self.client.federation.identity_providers - self.path_prefix = 'OS-FEDERATION' - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def test_positional_parameters_expect_fail(self): - """Ensure CrudManager raises TypeError exceptions. - - After passing wrong number of positional arguments - an exception should be raised. - - Operations to be tested: - * create() - * get() - * list() - * delete() - * update() - - """ - POS_PARAM_1 = uuid.uuid4().hex - POS_PARAM_2 = uuid.uuid4().hex - POS_PARAM_3 = uuid.uuid4().hex - - PARAMETERS = { - 'create': (POS_PARAM_1, POS_PARAM_2), - 'get': (POS_PARAM_1, POS_PARAM_2), - 'list': (POS_PARAM_1, POS_PARAM_2), - 'update': (POS_PARAM_1, POS_PARAM_2, POS_PARAM_3), - 'delete': (POS_PARAM_1, POS_PARAM_2) - } - - for f_name, args in PARAMETERS.items(): - self.assertRaises(TypeError, getattr(self.manager, f_name), - *args) - - def test_create(self): - ref = self.new_ref() - req_ref = ref.copy() - req_ref.pop('id') - - self.stub_entity('PUT', entity=ref, id=ref['id'], status_code=201) - - returned = self.manager.create(**ref) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - -class MappingTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(MappingTests, self).setUp() - self.key = 'mapping' - self.collection_key = 'mappings' - self.model = mappings.Mapping - self.manager = self.client.federation.mappings - self.path_prefix = 'OS-FEDERATION' - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('rules', [uuid.uuid4().hex, - uuid.uuid4().hex]) - return kwargs - - def test_create(self): - ref = self.new_ref() - manager_ref = ref.copy() - mapping_id = manager_ref.pop('id') - req_ref = ref.copy() - - self.stub_entity('PUT', entity=req_ref, id=mapping_id, - status_code=201) - - returned = self.manager.create(mapping_id=mapping_id, **manager_ref) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(manager_ref) - - -class ProtocolTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ProtocolTests, self).setUp() - self.key = 'protocol' - self.collection_key = 'protocols' - self.model = protocols.Protocol - self.manager = self.client.federation.protocols - self.path_prefix = 'OS-FEDERATION/identity_providers' - - def _transform_to_response(self, ref): - """Construct a response body from a dictionary.""" - response = copy.deepcopy(ref) - del response['identity_provider'] - return response - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('mapping_id', uuid.uuid4().hex) - kwargs.setdefault('identity_provider', uuid.uuid4().hex) - return kwargs - - def build_parts(self, idp_id, protocol_id=None): - """Build array used to construct mocking URL. - - Construct and return array with URL parts later used - by methods like utils.TestCase.stub_entity(). - Example of URL: - ``OS-FEDERATION/identity_providers/{idp_id}/ - protocols/{protocol_id}`` - - """ - parts = ['OS-FEDERATION', 'identity_providers', - idp_id, 'protocols'] - if protocol_id: - parts.append(protocol_id) - return parts - - def test_build_url_provide_base_url(self): - base_url = uuid.uuid4().hex - parameters = {'base_url': base_url} - url = self.manager.build_url(dict_args_in_out=parameters) - self.assertEqual('/'.join([base_url, self.collection_key]), url) - - def test_build_url_w_idp_id(self): - """Test whether kwargs ``base_url`` discards object's base_url. - - This test shows, that when ``base_url`` is specified in the - dict_args_in_out dictionary, values like ``identity_provider_id`` - are not taken into consideration while building the url. - - """ - base_url, identity_provider_id = uuid.uuid4().hex, uuid.uuid4().hex - parameters = { - 'base_url': base_url, - 'identity_provider_id': identity_provider_id - } - url = self.manager.build_url(dict_args_in_out=parameters) - self.assertEqual('/'.join([base_url, self.collection_key]), url) - - def test_build_url_default_base_url(self): - identity_provider_id = uuid.uuid4().hex - parameters = { - 'identity_provider_id': identity_provider_id - } - - url = self.manager.build_url(dict_args_in_out=parameters) - self.assertEqual( - '/'.join([self.manager.base_url, identity_provider_id, - self.manager.collection_key]), url) - - def test_create(self): - """Test creating federation protocol tied to an Identity Provider. - - URL to be tested: PUT /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - expected = self._transform_to_response(ref) - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - self.stub_entity('PUT', entity=expected, - parts=parts, status_code=201) - returned = self.manager.create( - protocol_id=ref['id'], - identity_provider=ref['identity_provider'], - mapping=ref['mapping_id']) - self.assertEqual(expected, returned.to_dict()) - request_body = {'mapping_id': ref['mapping_id']} - self.assertEntityRequestBodyIs(request_body) - - def test_get(self): - """Fetch federation protocol object. - - URL to be tested: GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - expected = self._transform_to_response(ref) - - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - self.stub_entity('GET', entity=expected, - parts=parts, status_code=201) - - returned = self.manager.get(ref['identity_provider'], - ref['id']) - self.assertIsInstance(returned, self.model) - self.assertEqual(expected, returned.to_dict()) - - def test_delete(self): - """Delete federation protocol object. - - URL to be tested: DELETE /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - - self.stub_entity('DELETE', parts=parts, status_code=204) - - self.manager.delete(ref['identity_provider'], - ref['id']) - - def test_list(self): - """Test listing all federation protocols tied to the Identity Provider. - - URL to be tested: GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols - - """ - def _ref_protocols(): - return { - 'id': uuid.uuid4().hex, - 'mapping_id': uuid.uuid4().hex - } - - ref = self.new_ref() - expected = [_ref_protocols() for _ in range(3)] - parts = self.build_parts(idp_id=ref['identity_provider']) - self.stub_entity('GET', parts=parts, - entity=expected, status_code=200) - - returned = self.manager.list(ref['identity_provider']) - for obj, ref_obj in zip(returned, expected): - self.assertEqual(obj.to_dict(), ref_obj) - - def test_list_by_id(self): - # The test in the parent class needs to be overridden because it - # assumes globally unique IDs, which is not the case with protocol IDs - # (which are contextualized per identity provider). - ref = self.new_ref() - super(ProtocolTests, self).test_list_by_id( - ref=ref, - identity_provider=ref['identity_provider'], - id=ref['id']) - - def test_list_params(self): - request_args = self.new_ref() - filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} - parts = self.build_parts(request_args['identity_provider']) - - # Return HTTP 401 as we don't accept such requests. - self.stub_entity('GET', parts=parts, status_code=401) - self.assertRaises(exceptions.Unauthorized, - self.manager.list, - request_args['identity_provider'], - **filter_kwargs) - self.assertQueryStringContains(**filter_kwargs) - - def test_update(self): - """Test updating federation protocol. - - URL to be tested: PATCH /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - expected = self._transform_to_response(ref) - - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - - self.stub_entity('PATCH', parts=parts, - entity=expected, status_code=200) - - returned = self.manager.update(ref['identity_provider'], - ref['id'], - mapping=ref['mapping_id']) - self.assertIsInstance(returned, self.model) - self.assertEqual(expected, returned.to_dict()) - request_body = {'mapping_id': ref['mapping_id']} - self.assertEntityRequestBodyIs(request_body) - - -class EntityManagerTests(utils.ClientTestCase): - def test_create_object_expect_fail(self): - self.assertRaises(TypeError, - base.EntityManager, - self.client) - - -class FederationProjectTests(utils.ClientTestCase): - - def setUp(self): - super(FederationProjectTests, self).setUp() - self.key = 'project' - self.collection_key = 'projects' - self.model = projects.Project - self.manager = self.client.federation.projects - self.URL = "%s%s" % (self.TEST_URL, '/auth/projects') - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_list_accessible_projects(self): - projects_ref = [self.new_ref(), self.new_ref()] - projects_json = { - self.collection_key: [self.new_ref(), self.new_ref()] - } - self.requests_mock.get(self.URL, json=projects_json) - returned_list = self.manager.list() - - self.assertEqual(len(projects_ref), len(returned_list)) - for project in returned_list: - self.assertIsInstance(project, self.model) - - -class K2KFederatedProjectTests(utils.TestCase): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - TEST_PASS = 'password' - REQUEST_ECP_URL = TEST_URL + '/auth/OS-FEDERATION/saml2/ecp' - - SP_ID = 'sp1' - SP_ROOT_URL = 'https://example.com/v3' - SP_URL = 'https://example.com/Shibboleth.sso/SAML2/ECP' - SP_AUTH_URL = (SP_ROOT_URL + - '/OS-FEDERATION/identity_providers' - '/testidp/protocols/saml2/auth') - - def setUp(self): - super(K2KFederatedProjectTests, self).setUp() - self.token_v3 = fixture.V3Token() - self.token_v3.add_service_provider( - self.SP_ID, self.SP_AUTH_URL, self.SP_URL) - self.session = session.Session() - self.collection_key = 'projects' - self.model = projects.Project - self.URL = '%s%s' % (self.SP_ROOT_URL, '/auth/projects') - self.k2kplugin = self.get_plugin() - self._mock_k2k_flow_urls() - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def _get_base_plugin(self): - self.stub_url('POST', ['auth', 'tokens'], - headers={'X-Subject-Token': uuid.uuid4().hex}, - json=self.token_v3) - return v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS) - - def _mock_k2k_flow_urls(self): - # We need to check the auth versions available - self.requests_mock.get( - self.TEST_URL, - json={'version': fixture.V3Discovery(self.TEST_URL)}, - headers={'Content-Type': 'application/json'}) - - # The identity provider receives a request for an ECP wrapped - # assertion. This assertion contains the user authentication info - # and will be presented to the service provider - self.requests_mock.register_uri( - 'POST', - self.REQUEST_ECP_URL, - content=six.b(k2k_fixtures.ECP_ENVELOPE), - headers={'Content-Type': 'application/vnd.paos+xml'}, - status_code=200) - - # The service provider is presented with the ECP wrapped assertion - # generated by the identity provider and should return a redirect - # (302 or 303) upon successful authentication - self.requests_mock.register_uri( - 'POST', - self.SP_URL, - content=six.b(k2k_fixtures.TOKEN_BASED_ECP), - headers={'Content-Type': 'application/vnd.paos+xml'}, - status_code=302) - - # Should not follow the redirect URL, but use the auth_url attribute - self.requests_mock.register_uri( - 'GET', - self.SP_AUTH_URL, - json=k2k_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': k2k_fixtures.UNSCOPED_TOKEN_HEADER}) - - def get_plugin(self, **kwargs): - kwargs.setdefault('base_plugin', self._get_base_plugin()) - kwargs.setdefault('service_provider', self.SP_ID) - return v3.Keystone2Keystone(**kwargs) - - def test_list_projects(self): - k2k_client = client.Client(session=self.session, auth=self.k2kplugin) - self.requests_mock.get(self.URL, json={ - self.collection_key: [self.new_ref(), self.new_ref()] - }) - self.requests_mock.get(self.SP_ROOT_URL, json={ - 'version': fixture.discovery.V3Discovery(self.SP_ROOT_URL) - }) - returned_list = k2k_client.federation.projects.list() - - self.assertThat(returned_list, matchers.HasLength(2)) - for project in returned_list: - self.assertIsInstance(project, self.model) - - -class FederationDomainTests(utils.ClientTestCase): - - def setUp(self): - super(FederationDomainTests, self).setUp() - self.key = 'domain' - self.collection_key = 'domains' - self.model = domains.Domain - self.manager = self.client.federation.domains - - self.URL = "%s%s" % (self.TEST_URL, '/auth/domains') - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - return kwargs - - def test_list_accessible_domains(self): - domains_ref = [self.new_ref(), self.new_ref()] - domains_json = { - self.collection_key: domains_ref - } - self.requests_mock.get(self.URL, json=domains_json) - returned_list = self.manager.list() - self.assertEqual(len(domains_ref), len(returned_list)) - for domain in returned_list: - self.assertIsInstance(domain, self.model) - - -class FederatedTokenTests(utils.ClientTestCase): - - def setUp(self): - super(FederatedTokenTests, self).setUp() - token = fixture.V3FederationToken() - token.set_project_scope() - token.add_role() - self.federated_token = access.AccessInfo.factory(body=token) - - def test_federated_property_federated_token(self): - """Check if is_federated property returns expected value.""" - self.assertTrue(self.federated_token.is_federated) - - def test_get_user_domain_name(self): - """Ensure a federated user's domain name does not exist.""" - self.assertIsNone(self.federated_token.user_domain_name) - - def test_get_user_domain_id(self): - """Ensure a federated user's domain ID does not exist.""" - self.assertEqual('Federated', self.federated_token.user_domain_id) - - -class ServiceProviderTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ServiceProviderTests, self).setUp() - self.key = 'service_provider' - self.collection_key = 'service_providers' - self.model = service_providers.ServiceProvider - self.manager = self.client.federation.service_providers - self.path_prefix = 'OS-FEDERATION' - - def new_ref(self, **kwargs): - kwargs.setdefault('auth_url', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('sp_url', uuid.uuid4().hex) - return kwargs - - def test_positional_parameters_expect_fail(self): - """Ensure CrudManager raises TypeError exceptions. - - After passing wrong number of positional arguments - an exception should be raised. - - Operations to be tested: - * create() - * get() - * list() - * delete() - * update() - - """ - POS_PARAM_1 = uuid.uuid4().hex - POS_PARAM_2 = uuid.uuid4().hex - POS_PARAM_3 = uuid.uuid4().hex - - PARAMETERS = { - 'create': (POS_PARAM_1, POS_PARAM_2), - 'get': (POS_PARAM_1, POS_PARAM_2), - 'list': (POS_PARAM_1, POS_PARAM_2), - 'update': (POS_PARAM_1, POS_PARAM_2, POS_PARAM_3), - 'delete': (POS_PARAM_1, POS_PARAM_2) - } - - for f_name, args in PARAMETERS.items(): - self.assertRaises(TypeError, getattr(self.manager, f_name), - *args) - - def test_create(self): - ref = self.new_ref() - - # req_ref argument allows you to specify a different - # signature for the request when the manager does some - # conversion before doing the request (e.g. converting - # from datetime object to timestamp string) - req_ref = ref.copy() - req_ref.pop('id') - - self.stub_entity('PUT', entity=ref, id=ref['id'], status_code=201) - - returned = self.manager.create(**ref) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) diff --git a/keystoneclient/tests/unit/v3/test_groups.py b/keystoneclient/tests/unit/v3/test_groups.py deleted file mode 100644 index 90fff0e6..00000000 --- a/keystoneclient/tests/unit/v3/test_groups.py +++ /dev/null @@ -1,58 +0,0 @@ -# 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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import groups - - -class GroupTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(GroupTests, self).setUp() - self.key = 'group' - self.collection_key = 'groups' - self.model = groups.Group - self.manager = self.client.groups - - def new_ref(self, **kwargs): - kwargs = super(GroupTests, self).new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_list_groups_for_user(self): - user_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['users', user_id, self.collection_key], - status_code=200, entity=ref_list) - - returned_list = self.manager.list(user=user_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_list_groups_for_domain(self): - ref_list = [self.new_ref(), self.new_ref()] - domain_id = uuid.uuid4().hex - - self.stub_entity('GET', - [self.collection_key], - status_code=200, entity=ref_list) - - returned_list = self.manager.list(domain=domain_id) - self.assertTrue(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - self.assertQueryStringIs('domain_id=%s' % domain_id) diff --git a/keystoneclient/tests/unit/v3/test_oauth1.py b/keystoneclient/tests/unit/v3/test_oauth1.py deleted file mode 100644 index f939244d..00000000 --- a/keystoneclient/tests/unit/v3/test_oauth1.py +++ /dev/null @@ -1,290 +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. - -import uuid - -import mock -import six -from six.moves.urllib import parse as urlparse -from testtools import matchers - -from keystoneclient import session -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils -from keystoneclient import utils as client_utils -from keystoneclient.v3.contrib.oauth1 import access_tokens -from keystoneclient.v3.contrib.oauth1 import auth -from keystoneclient.v3.contrib.oauth1 import consumers -from keystoneclient.v3.contrib.oauth1 import request_tokens - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class ConsumerTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - if oauth1 is None: - self.skipTest('oauthlib package not available') - - super(ConsumerTests, self).setUp() - self.key = 'consumer' - self.collection_key = 'consumers' - self.model = consumers.Consumer - self.manager = self.client.oauth1.consumers - self.path_prefix = 'OS-OAUTH1' - - def new_ref(self, **kwargs): - kwargs = super(ConsumerTests, self).new_ref(**kwargs) - kwargs.setdefault('description', uuid.uuid4().hex) - return kwargs - - def test_description_is_optional(self): - consumer_id = uuid.uuid4().hex - resp_ref = {'consumer': {'description': None, - 'id': consumer_id}} - - self.stub_url('POST', - [self.path_prefix, self.collection_key], - status_code=201, json=resp_ref) - - consumer = self.manager.create() - self.assertEqual(consumer_id, consumer.id) - self.assertIsNone(consumer.description) - - def test_description_not_included(self): - consumer_id = uuid.uuid4().hex - resp_ref = {'consumer': {'id': consumer_id}} - - self.stub_url('POST', - [self.path_prefix, self.collection_key], - status_code=201, json=resp_ref) - - consumer = self.manager.create() - self.assertEqual(consumer_id, consumer.id) - - -class TokenTests(object): - def _new_oauth_token(self): - key = uuid.uuid4().hex - secret = uuid.uuid4().hex - params = {'oauth_token': key, 'oauth_token_secret': secret} - token = urlparse.urlencode(params) - return (key, secret, token) - - def _new_oauth_token_with_expires_at(self): - key, secret, token = self._new_oauth_token() - expires_at = client_utils.strtime() - params = {'oauth_token': key, - 'oauth_token_secret': secret, - 'oauth_expires_at': expires_at} - token = urlparse.urlencode(params) - return (key, secret, expires_at, token) - - def _validate_oauth_headers(self, auth_header, oauth_client): - """Validate data in the headers. - - Assert that the data in the headers matches the data - that is produced from oauthlib. - """ - self.assertThat(auth_header, matchers.StartsWith('OAuth ')) - parameters = dict( - oauth1.rfc5849.utils.parse_authorization_header(auth_header)) - - self.assertEqual('HMAC-SHA1', parameters['oauth_signature_method']) - self.assertEqual('1.0', parameters['oauth_version']) - self.assertIsInstance(parameters['oauth_nonce'], six.string_types) - self.assertEqual(oauth_client.client_key, - parameters['oauth_consumer_key']) - if oauth_client.resource_owner_key: - self.assertEqual(oauth_client.resource_owner_key, - parameters['oauth_token'],) - if oauth_client.verifier: - self.assertEqual(oauth_client.verifier, - parameters['oauth_verifier']) - if oauth_client.callback_uri: - self.assertEqual(oauth_client.callback_uri, - parameters['oauth_callback']) - return parameters - - -class RequestTokenTests(utils.ClientTestCase, TokenTests): - def setUp(self): - if oauth1 is None: - self.skipTest('oauthlib package not available') - - super(RequestTokenTests, self).setUp() - self.model = request_tokens.RequestToken - self.manager = self.client.oauth1.request_tokens - self.path_prefix = 'OS-OAUTH1' - - def test_authorize_request_token(self): - request_key = uuid.uuid4().hex - info = {'id': request_key, - 'key': request_key, - 'secret': uuid.uuid4().hex} - request_token = request_tokens.RequestToken(self.manager, info) - - verifier = uuid.uuid4().hex - resp_ref = {'token': {'oauth_verifier': verifier}} - self.stub_url('PUT', - [self.path_prefix, 'authorize', request_key], - status_code=200, json=resp_ref) - - # Assert the manager is returning the expected data - role_id = uuid.uuid4().hex - token = request_token.authorize([role_id]) - self.assertEqual(verifier, token.oauth_verifier) - - # Assert that the request was sent in the expected structure - exp_body = {'roles': [{'id': role_id}]} - self.assertRequestBodyIs(json=exp_body) - - def test_create_request_token(self): - project_id = uuid.uuid4().hex - consumer_key = uuid.uuid4().hex - consumer_secret = uuid.uuid4().hex - - request_key, request_secret, resp_ref = self._new_oauth_token() - - headers = {'Content-Type': 'application/x-www-form-urlencoded'} - self.stub_url('POST', [self.path_prefix, 'request_token'], - status_code=201, text=resp_ref, headers=headers) - - # Assert the manager is returning request token object - request_token = self.manager.create(consumer_key, consumer_secret, - project_id) - self.assertIsInstance(request_token, self.model) - self.assertEqual(request_key, request_token.key) - self.assertEqual(request_secret, request_token.secret) - - # Assert that the project id is in the header - self.assertRequestHeaderEqual('requested-project-id', project_id) - req_headers = self.requests_mock.last_request.headers - - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - signature_method=oauth1.SIGNATURE_HMAC, - callback_uri="oob") - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - - -class AccessTokenTests(utils.ClientTestCase, TokenTests): - def setUp(self): - if oauth1 is None: - self.skipTest('oauthlib package not available') - - super(AccessTokenTests, self).setUp() - self.manager = self.client.oauth1.access_tokens - self.model = access_tokens.AccessToken - self.path_prefix = 'OS-OAUTH1' - - def test_create_access_token_expires_at(self): - verifier = uuid.uuid4().hex - consumer_key = uuid.uuid4().hex - consumer_secret = uuid.uuid4().hex - request_key = uuid.uuid4().hex - request_secret = uuid.uuid4().hex - - t = self._new_oauth_token_with_expires_at() - access_key, access_secret, expires_at, resp_ref = t - - headers = {'Content-Type': 'application/x-www-form-urlencoded'} - self.stub_url('POST', [self.path_prefix, 'access_token'], - status_code=201, text=resp_ref, headers=headers) - - # Assert that the manager creates an access token object - access_token = self.manager.create(consumer_key, consumer_secret, - request_key, request_secret, - verifier) - self.assertIsInstance(access_token, self.model) - self.assertEqual(access_key, access_token.key) - self.assertEqual(access_secret, access_token.secret) - self.assertEqual(expires_at, access_token.expires) - - req_headers = self.requests_mock.last_request.headers - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - resource_owner_key=request_key, - resource_owner_secret=request_secret, - signature_method=oauth1.SIGNATURE_HMAC, - verifier=verifier) - - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - - -class AuthenticateWithOAuthTests(utils.TestCase, TokenTests): - def setUp(self): - super(AuthenticateWithOAuthTests, self).setUp() - if oauth1 is None: - self.skipTest('optional package oauthlib is not installed') - - def test_oauth_authenticate_success(self): - consumer_key = uuid.uuid4().hex - consumer_secret = uuid.uuid4().hex - access_key = uuid.uuid4().hex - access_secret = uuid.uuid4().hex - - # Just use an existing project scoped token and change - # the methods to oauth1, and add an OS-OAUTH1 section. - oauth_token = client_fixtures.project_scoped_token() - oauth_token['methods'] = ["oauth1"] - oauth_token['OS-OAUTH1'] = {"consumer_id": consumer_key, - "access_token_id": access_key} - self.stub_auth(json=oauth_token) - - with self.deprecations.expect_deprecations_here(): - a = auth.OAuth(self.TEST_URL, consumer_key=consumer_key, - consumer_secret=consumer_secret, - access_key=access_key, - access_secret=access_secret) - s = session.Session(auth=a) - t = s.get_token() - self.assertEqual(self.TEST_TOKEN, t) - - OAUTH_REQUEST_BODY = { - "auth": { - "identity": { - "methods": ["oauth1"], - "oauth1": {} - } - } - } - - self.assertRequestBodyIs(json=OAUTH_REQUEST_BODY) - - # Assert that the headers have the same oauthlib data - req_headers = self.requests_mock.last_request.headers - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_key, - resource_owner_secret=access_secret, - signature_method=oauth1.SIGNATURE_HMAC) - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - - -class TestOAuthLibModule(utils.TestCase): - - def test_no_oauthlib_installed(self): - with mock.patch.object(auth, 'oauth1', None): - self.assertRaises(NotImplementedError, - auth.OAuth, - self.TEST_URL, - consumer_key=uuid.uuid4().hex, - consumer_secret=uuid.uuid4().hex, - access_key=uuid.uuid4().hex, - access_secret=uuid.uuid4().hex) diff --git a/keystoneclient/tests/unit/v3/test_policies.py b/keystoneclient/tests/unit/v3/test_policies.py deleted file mode 100644 index 47be4838..00000000 --- a/keystoneclient/tests/unit/v3/test_policies.py +++ /dev/null @@ -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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import policies - - -class PolicyTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(PolicyTests, self).setUp() - self.key = 'policy' - self.collection_key = 'policies' - self.model = policies.Policy - self.manager = self.client.policies - - def new_ref(self, **kwargs): - kwargs = super(PolicyTests, self).new_ref(**kwargs) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('blob', uuid.uuid4().hex) - return kwargs diff --git a/keystoneclient/tests/unit/v3/test_projects.py b/keystoneclient/tests/unit/v3/test_projects.py deleted file mode 100644 index 48477ed4..00000000 --- a/keystoneclient/tests/unit/v3/test_projects.py +++ /dev/null @@ -1,314 +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. - -import uuid - -from keystoneauth1 import exceptions as ksa_exceptions - -from keystoneclient import exceptions as ksc_exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import projects - - -class ProjectTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ProjectTests, self).setUp() - self.key = 'project' - self.collection_key = 'projects' - self.model = projects.Project - self.manager = self.client.projects - - def new_ref(self, **kwargs): - kwargs = super(ProjectTests, self).new_ref(**kwargs) - return self._new_project_ref(ref=kwargs) - - def _new_project_ref(self, ref=None): - ref = ref or {} - ref.setdefault('domain_id', uuid.uuid4().hex) - ref.setdefault('enabled', True) - ref.setdefault('name', uuid.uuid4().hex) - return ref - - def test_list_projects_for_user(self): - ref_list = [self.new_ref(), self.new_ref()] - user_id = uuid.uuid4().hex - - self.stub_entity('GET', - ['users', user_id, self.collection_key], - entity=ref_list) - - returned_list = self.manager.list(user=user_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_list_projects_for_domain(self): - ref_list = [self.new_ref(), self.new_ref()] - domain_id = uuid.uuid4().hex - - self.stub_entity('GET', [self.collection_key], - entity=ref_list) - - returned_list = self.manager.list(domain=domain_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - self.assertQueryStringIs('domain_id=%s' % domain_id) - - def test_create_with_parent(self): - parent_ref = self.new_ref() - parent_ref['parent_id'] = uuid.uuid4().hex - parent = self.test_create(ref=parent_ref) - parent.id = parent_ref['id'] - - # Create another project under 'parent' in the hierarchy - ref = self.new_ref() - ref['parent_id'] = parent.id - - child_ref = ref.copy() - del child_ref['parent_id'] - child_ref['parent'] = parent - - # test_create() pops the 'id' of the mocked response - del ref['id'] - - # Resource objects may peform lazy-loading. The create() method of - # ProjectManager will try to access the 'uuid' attribute of the parent - # object, which will trigger a call to fetch the Resource attributes. - self.stub_entity('GET', id=parent_ref['id'], entity=parent_ref) - self.test_create(ref=child_ref, req_ref=ref) - - def test_create_with_parent_id(self): - ref = self._new_project_ref() - ref['parent_id'] = uuid.uuid4().hex - - self.stub_entity('POST', entity=ref, status_code=201) - - returned = self.manager.create(name=ref['name'], - domain=ref['domain_id'], - parent_id=ref['parent_id']) - - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(ref) - - def test_create_with_parent_and_parent_id(self): - ref = self._new_project_ref() - ref['parent_id'] = uuid.uuid4().hex - - self.stub_entity('POST', entity=ref, status_code=201) - - # Should ignore the 'parent_id' argument since we are also passing - # 'parent' - returned = self.manager.create(name=ref['name'], - domain=ref['domain_id'], - parent=ref['parent_id'], - parent_id=uuid.uuid4().hex) - - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(ref) - - def _create_projects_hierarchy(self, hierarchy_size=3): - """Create a project hierarchy with specified size. - - :param hierarchy_size: the desired hierarchy size, default is 3. - - :returns: a list of the projects in the created hierarchy. - - """ - ref = self.new_ref() - project_id = ref['id'] - projects = [ref] - - for i in range(1, hierarchy_size): - new_ref = self.new_ref() - new_ref['parent_id'] = project_id - projects.append(new_ref) - project_id = new_ref['id'] - - return projects - - def test_get_with_subtree_as_ids(self): - projects = self._create_projects_hierarchy() - ref = projects[0] - - # We will query for projects[0] subtree, it should include projects[1] - # and projects[2] structured like the following: - # { - # projects[1]: { - # projects[2]: None - # } - # } - ref['subtree'] = { - projects[1]['id']: { - projects[2]['id']: None - } - } - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], subtree_as_ids=True) - self.assertQueryStringIs('subtree_as_ids') - self.assertEqual(ref['subtree'], returned.subtree) - - def test_get_with_parents_as_ids(self): - projects = self._create_projects_hierarchy() - ref = projects[2] - - # We will query for projects[2] parents, it should include projects[1] - # and projects[0] structured like the following: - # { - # projects[1]: { - # projects[0]: None - # } - # } - ref['parents'] = { - projects[1]['id']: { - projects[0]['id']: None - } - } - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], parents_as_ids=True) - self.assertQueryStringIs('parents_as_ids') - self.assertEqual(ref['parents'], returned.parents) - - def test_get_with_parents_as_ids_and_subtree_as_ids(self): - ref = self.new_ref() - projects = self._create_projects_hierarchy() - ref = projects[1] - - # We will query for projects[1] subtree and parents. The subtree should - # include projects[2] and the parents should include projects[2]. - ref['parents'] = { - projects[0]['id']: None - } - ref['subtree'] = { - projects[2]['id']: None - } - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], - parents_as_ids=True, - subtree_as_ids=True) - self.assertQueryStringIs('subtree_as_ids&parents_as_ids') - self.assertEqual(ref['parents'], returned.parents) - self.assertEqual(ref['subtree'], returned.subtree) - - def test_get_with_subtree_as_list(self): - projects = self._create_projects_hierarchy() - ref = projects[0] - - ref['subtree_as_list'] = [] - for i in range(1, len(projects)): - ref['subtree_as_list'].append(projects[i]) - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], subtree_as_list=True) - self.assertQueryStringIs('subtree_as_list') - for i in range(1, len(projects)): - for attr in projects[i]: - child = getattr(returned, 'subtree_as_list')[i - 1] - self.assertEqual( - child[attr], - projects[i][attr], - 'Expected different %s' % attr) - - def test_get_with_parents_as_list(self): - projects = self._create_projects_hierarchy() - ref = projects[2] - - ref['parents_as_list'] = [] - for i in range(0, len(projects) - 1): - ref['parents_as_list'].append(projects[i]) - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], parents_as_list=True) - self.assertQueryStringIs('parents_as_list') - for i in range(0, len(projects) - 1): - for attr in projects[i]: - parent = getattr(returned, 'parents_as_list')[i] - self.assertEqual( - parent[attr], - projects[i][attr], - 'Expected different %s' % attr) - - def test_get_with_parents_as_list_and_subtree_as_list(self): - ref = self.new_ref() - projects = self._create_projects_hierarchy() - ref = projects[1] - - ref['parents_as_list'] = [projects[0]] - ref['subtree_as_list'] = [projects[2]] - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], - parents_as_list=True, - subtree_as_list=True) - self.assertQueryStringIs('subtree_as_list&parents_as_list') - - for attr in projects[0]: - parent = getattr(returned, 'parents_as_list')[0] - self.assertEqual( - parent[attr], - projects[0][attr], - 'Expected different %s' % attr) - - for attr in projects[2]: - child = getattr(returned, 'subtree_as_list')[0] - self.assertEqual( - child[attr], - projects[2][attr], - 'Expected different %s' % attr) - - def test_get_with_invalid_parameters_combination(self): - # subtree_as_list and subtree_as_ids can not be included at the - # same time in the call. - self.assertRaises(ksc_exceptions.ValidationError, - self.manager.get, - project=uuid.uuid4().hex, - subtree_as_list=True, - subtree_as_ids=True) - - # parents_as_list and parents_as_ids can not be included at the - # same time in the call. - self.assertRaises(ksc_exceptions.ValidationError, - self.manager.get, - project=uuid.uuid4().hex, - parents_as_list=True, - parents_as_ids=True) - - def test_update_with_parent_project(self): - ref = self.new_ref() - ref['parent_id'] = uuid.uuid4().hex - - self.stub_entity('PATCH', id=ref['id'], entity=ref, status_code=403) - req_ref = ref.copy() - req_ref.pop('id') - - # NOTE(rodrigods): this is the expected behaviour of the Identity - # server, a different implementation might not fail this request. - self.assertRaises(ksa_exceptions.Forbidden, self.manager.update, - ref['id'], **utils.parameterize(req_ref)) diff --git a/keystoneclient/tests/unit/v3/test_regions.py b/keystoneclient/tests/unit/v3/test_regions.py deleted file mode 100644 index 90ddfdc6..00000000 --- a/keystoneclient/tests/unit/v3/test_regions.py +++ /dev/null @@ -1,37 +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. - - -import uuid - - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import regions - - -class RegionTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(RegionTests, self).setUp() - self.key = 'region' - self.collection_key = 'regions' - self.model = regions.Region - self.manager = self.client.regions - - def new_ref(self, **kwargs): - kwargs = super(RegionTests, self).new_ref(**kwargs) - kwargs.setdefault('enabled', True) - kwargs.setdefault('id', uuid.uuid4().hex) - return kwargs - - def test_update_enabled_defaults_to_none(self): - super(RegionTests, self).test_update( - req_ref={'description': uuid.uuid4().hex}) diff --git a/keystoneclient/tests/unit/v3/test_role_assignments.py b/keystoneclient/tests/unit/v3/test_role_assignments.py deleted file mode 100644 index b24799cb..00000000 --- a/keystoneclient/tests/unit/v3/test_role_assignments.py +++ /dev/null @@ -1,262 +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 import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import role_assignments - - -class RoleAssignmentsTests(utils.ClientTestCase, utils.CrudTests): - - def setUp(self): - super(RoleAssignmentsTests, self).setUp() - self.key = 'role_assignment' - self.collection_key = 'role_assignments' - self.model = role_assignments.RoleAssignment - self.manager = self.client.role_assignments - self.TEST_USER_DOMAIN_LIST = [{ - 'role': { - 'id': self.TEST_ROLE_ID - }, - 'scope': { - 'domain': { - 'id': self.TEST_DOMAIN_ID - } - }, - 'user': { - 'id': self.TEST_USER_ID - } - }] - self.TEST_GROUP_PROJECT_LIST = [{ - 'group': { - 'id': self.TEST_GROUP_ID - }, - 'role': { - 'id': self.TEST_ROLE_ID - }, - 'scope': { - 'project': { - 'id': self.TEST_TENANT_ID - } - } - }] - self.TEST_USER_PROJECT_LIST = [{ - 'user': { - 'id': self.TEST_USER_ID - }, - 'role': { - 'id': self.TEST_ROLE_ID - }, - 'scope': { - 'project': { - 'id': self.TEST_TENANT_ID - } - } - }] - - self.TEST_ALL_RESPONSE_LIST = (self.TEST_USER_PROJECT_LIST + - self.TEST_GROUP_PROJECT_LIST + - self.TEST_USER_DOMAIN_LIST) - - def _assert_returned_list(self, ref_list, returned_list): - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_list_by_id(self): - # It doesn't make sense to "list role assignments by ID" at all, given - # that they don't have globally unique IDs in the first place. But - # calling RoleAssignmentsManager.list(id=...) should still raise a - # TypeError when given an unexpected keyword argument 'id', so we don't - # actually have to modify the test in the superclass... I just wanted - # to make a note here in case the superclass changes. - super(RoleAssignmentsTests, self).test_list_by_id() - - def test_list_params(self): - ref_list = self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.project.id=%s&user.id=%s' % - (self.TEST_TENANT_ID, self.TEST_USER_ID)], - entity=ref_list) - - returned_list = self.manager.list(user=self.TEST_USER_ID, - project=self.TEST_TENANT_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.project.id': self.TEST_TENANT_ID, - 'user.id': self.TEST_USER_ID} - self.assertQueryStringContains(**kwargs) - - def test_all_assignments_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key], - entity=ref_list) - - returned_list = self.manager.list() - self._assert_returned_list(ref_list, returned_list) - - kwargs = {} - self.assertQueryStringContains(**kwargs) - - def test_project_assignments_list(self): - ref_list = self.TEST_GROUP_PROJECT_LIST + self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.project.id=%s' % self.TEST_TENANT_ID], - entity=ref_list) - - returned_list = self.manager.list(project=self.TEST_TENANT_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.project.id': self.TEST_TENANT_ID} - self.assertQueryStringContains(**kwargs) - - def test_project_assignments_list_include_subtree(self): - ref_list = self.TEST_GROUP_PROJECT_LIST + self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.project.id=%s&include_subtree=True' % - self.TEST_TENANT_ID], - entity=ref_list) - - returned_list = self.manager.list(project=self.TEST_TENANT_ID, - include_subtree=True) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.project.id': self.TEST_TENANT_ID, - 'include_subtree': 'True'} - self.assertQueryStringContains(**kwargs) - - def test_domain_assignments_list(self): - ref_list = self.TEST_USER_DOMAIN_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.domain.id=%s' % self.TEST_DOMAIN_ID], - entity=ref_list) - - returned_list = self.manager.list(domain=self.TEST_DOMAIN_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.domain.id': self.TEST_DOMAIN_ID} - self.assertQueryStringContains(**kwargs) - - def test_group_assignments_list(self): - ref_list = self.TEST_GROUP_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?group.id=%s' % self.TEST_GROUP_ID], - entity=ref_list) - - returned_list = self.manager.list(group=self.TEST_GROUP_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'group.id': self.TEST_GROUP_ID} - self.assertQueryStringContains(**kwargs) - - def test_user_assignments_list(self): - ref_list = self.TEST_USER_DOMAIN_LIST + self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?user.id=%s' % self.TEST_USER_ID], - entity=ref_list) - - returned_list = self.manager.list(user=self.TEST_USER_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'user.id': self.TEST_USER_ID} - self.assertQueryStringContains(**kwargs) - - def test_effective_assignments_list(self): - ref_list = self.TEST_USER_PROJECT_LIST + self.TEST_USER_DOMAIN_LIST - self.stub_entity('GET', - [self.collection_key, - '?effective=True'], - entity=ref_list) - - returned_list = self.manager.list(effective=True) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'effective': 'True'} - self.assertQueryStringContains(**kwargs) - - def test_include_names_assignments_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key, - '?include_names'], - entity=ref_list) - - returned_list = self.manager.list(include_names=True) - self._assert_returned_list(ref_list, returned_list) - kwargs = {'include_names': 'True'} - self.assertQueryStringContains(**kwargs) - - def test_role_assignments_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key, - '?role.id=' + self.TEST_ROLE_ID], - entity=ref_list) - - returned_list = self.manager.list(role=self.TEST_ROLE_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'role.id': self.TEST_ROLE_ID} - self.assertQueryStringContains(**kwargs) - - def test_role_assignments_inherited_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.OS-INHERIT:inherited_to=projects'], - entity=ref_list - ) - - returned_list = self.manager.list( - os_inherit_extension_inherited_to='projects') - self._assert_returned_list(ref_list, returned_list) - - query_string = 'scope.OS-INHERIT:inherited_to=projects' - self.assertQueryStringIs(query_string) - - def test_domain_and_project_list(self): - # Should only accept either domain or project, never both - self.assertRaises(exceptions.ValidationError, - self.manager.list, - domain=self.TEST_DOMAIN_ID, - project=self.TEST_TENANT_ID) - - def test_user_and_group_list(self): - # Should only accept either user or group, never both - self.assertRaises(exceptions.ValidationError, self.manager.list, - user=self.TEST_USER_ID, group=self.TEST_GROUP_ID) - - def test_create(self): - # Create not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.create) - - def test_update(self): - # Update not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.update) - - def test_delete(self): - # Delete not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.delete) - - def test_get(self): - # Get not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.get) - - def test_find(self): - # Find not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.find) diff --git a/keystoneclient/tests/unit/v3/test_roles.py b/keystoneclient/tests/unit/v3/test_roles.py deleted file mode 100644 index 51d9fc73..00000000 --- a/keystoneclient/tests/unit/v3/test_roles.py +++ /dev/null @@ -1,824 +0,0 @@ -# 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. - -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import roles -from testtools import matchers - - -class RoleTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(RoleTests, self).setUp() - self.key = 'role' - self.collection_key = 'roles' - self.model = roles.Role - self.manager = self.client.roles - - def new_ref(self, **kwargs): - kwargs = super(RoleTests, self).new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def _new_domain_ref(self, **kwargs): - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_create_with_domain_id(self): - ref = self.new_ref() - ref['domain_id'] = uuid.uuid4().hex - self.test_create(ref=ref) - - def test_create_with_domain(self): - ref = self.new_ref() - domain_ref = self._new_domain_ref() - domain_ref['id'] = uuid.uuid4().hex - ref['domain_id'] = domain_ref['id'] - - self.stub_entity('POST', entity=ref, status_code=201) - returned = self.manager.create(name=ref['name'], - domain=domain_ref) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - - def test_domain_role_grant(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['domains', domain_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, user=user_id) - - def test_domain_role_grant_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'domains', domain_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, user=user_id, - os_inherit_extension_inherited=True) - - def test_project_role_grant_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'projects', project_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.grant(role=ref['id'], project=project_id, user=user_id, - os_inherit_extension_inherited=True) - - def test_domain_group_role_grant(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['domains', domain_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, group=group_id) - - def test_domain_group_role_grant_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'domains', domain_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, group=group_id, - os_inherit_extension_inherited=True) - - def test_project_group_role_grant_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'projects', project_id, 'groups', - group_id, self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.grant(role=ref['id'], project=project_id, group=group_id, - os_inherit_extension_inherited=True) - - def test_domain_role_list(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['domains', domain_id, 'users', user_id, - self.collection_key], entity=ref_list) - - self.manager.list(domain=domain_id, user=user_id) - - def test_domain_role_list_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'domains', domain_id, 'users', user_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(domain=domain_id, user=user_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_project_user_role_list_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'projects', project_id, 'users', user_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(project=project_id, user=user_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_domain_group_role_list(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['domains', domain_id, 'groups', group_id, - self.collection_key], entity=ref_list) - - self.manager.list(domain=domain_id, group=group_id) - - def test_domain_group_role_list_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'domains', domain_id, 'groups', group_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(domain=domain_id, group=group_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_project_group_role_list_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'projects', project_id, 'groups', group_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(project=project_id, group=group_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_domain_role_check(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['domains', domain_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, - user=user_id) - - def test_domain_role_check_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'domains', domain_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_project_role_check_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'projects', project_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], project=project_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_domain_group_role_check(self): - return - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['domains', domain_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, group=group_id) - - def test_domain_group_role_check_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'domains', domain_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, - group=group_id, os_inherit_extension_inherited=True) - - def test_project_group_role_check_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'projects', project_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], project=project_id, - group=group_id, os_inherit_extension_inherited=True) - - def test_domain_role_revoke(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['domains', domain_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], domain=domain_id, user=user_id) - - def test_domain_group_role_revoke(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['domains', domain_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], domain=domain_id, group=group_id) - - def test_domain_role_revoke_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'domains', domain_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.revoke(role=ref['id'], domain=domain_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_project_role_revoke_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'projects', project_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_domain_group_role_revoke_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'domains', domain_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=200) - - self.manager.revoke(role=ref['id'], domain=domain_id, - group=group_id, - os_inherit_extension_inherited=True) - - def test_project_group_role_revoke_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'projects', project_id, 'groups', - group_id, self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, - group=group_id, - os_inherit_extension_inherited=True) - - def test_project_role_grant(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['projects', project_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], project=project_id, user=user_id) - - def test_project_group_role_grant(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['projects', project_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], project=project_id, group=group_id) - - def test_project_role_list(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['projects', project_id, 'users', user_id, - self.collection_key], entity=ref_list) - - self.manager.list(project=project_id, user=user_id) - - def test_project_group_role_list(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['projects', project_id, 'groups', group_id, - self.collection_key], entity=ref_list) - - self.manager.list(project=project_id, group=group_id) - - def test_project_role_check(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['projects', project_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=200) - - self.manager.check(role=ref['id'], project=project_id, user=user_id) - - def test_project_group_role_check(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['projects', project_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=200) - - self.manager.check(role=ref['id'], project=project_id, group=group_id) - - def test_project_role_revoke(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['projects', project_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, user=user_id) - - def test_project_group_role_revoke(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['projects', project_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, group=group_id) - - def test_domain_project_role_grant_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.grant, - role=ref['id'], - domain=domain_id, - project=project_id, - user=user_id) - - def test_domain_project_role_list_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - - self.assertRaises( - exceptions.ValidationError, - self.manager.list, - domain=domain_id, - project=project_id, - user=user_id) - - def test_domain_project_role_check_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.check, - role=ref['id'], - domain=domain_id, - project=project_id, - user=user_id) - - def test_domain_project_role_revoke_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.revoke, - role=ref['id'], - domain=domain_id, - project=project_id, - user=user_id) - - def test_user_group_role_grant_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.grant, - role=ref['id'], - project=project_id, - group=group_id, - user=user_id) - - def test_user_group_role_list_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.assertRaises( - exceptions.ValidationError, - self.manager.list, - project=project_id, - group=group_id, - user=user_id) - - def test_user_group_role_check_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.check, - role=ref['id'], - project=project_id, - group=group_id, - user=user_id) - - def test_user_group_role_revoke_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.revoke, - role=ref['id'], - project=project_id, - group=group_id, - user=user_id) - - -class DeprecatedImpliedRoleTests(utils.ClientTestCase): - def setUp(self): - super(DeprecatedImpliedRoleTests, self).setUp() - self.key = 'role' - self.collection_key = 'roles' - self.model = roles.Role - self.manager = self.client.roles - - def test_implied_create(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": { - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }, - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - } - } - - self.stub_url('PUT', - ['roles', prior_id, 'implies', implied_id], - json=mock_response, - status_code=201) - - with self.deprecations.expect_deprecations_here(): - manager_result = self.manager.create_implied(prior_id, implied_id) - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - -class ImpliedRoleTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ImpliedRoleTests, self).setUp() - self.key = 'role_inference' - self.collection_key = 'role_inferences' - self.model = roles.InferenceRule - self.manager = self.client.inference_rules - - def test_check(self): - prior_role_id = uuid.uuid4().hex - implied_role_id = uuid.uuid4().hex - self.stub_url('HEAD', - ['roles', prior_role_id, 'implies', implied_role_id], - status_code=200) - - result = self.manager.check(prior_role_id, implied_role_id) - self.assertTrue(result) - - def test_get(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": { - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }, - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - } - } - - self.stub_url('GET', - ['roles', prior_id, 'implies', implied_id], - json=mock_response, - status_code=200) - - manager_result = self.manager.get(prior_id, implied_id) - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - def test_create(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": { - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }, - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - } - } - - self.stub_url('PUT', - ['roles', prior_id, 'implies', implied_id], - json=mock_response, - status_code=201) - - manager_result = self.manager.create(prior_id, implied_id) - - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - def test_delete(self): - prior_role_id = uuid.uuid4().hex - implied_role_id = uuid.uuid4().hex - self.stub_url('DELETE', - ['roles', prior_role_id, 'implies', implied_role_id], - status_code=204) - - status, body = self.manager.delete(prior_role_id, implied_role_id) - self.assertEqual(204, status.status_code) - self.assertIsNone(body) - - def test_list_role_inferences(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inferences": [{ - "implies": [{ - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }], - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - }] - } - - self.stub_url('GET', - ['role_inferences'], - json=mock_response, - status_code=200) - manager_result = self.manager.list_inference_roles() - self.assertEqual(1, len(manager_result)) - self.assertIsInstance(manager_result[0], roles.InferenceRule) - self.assertEqual(mock_response['role_inferences'][0]['implies'], - manager_result[0].implies) - self.assertEqual(mock_response['role_inferences'][0]['prior_role'], - manager_result[0].prior_role) - - def test_list(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": [{ - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }], - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - }, - "links": {"self": "http://host/v3/roles/%s/implies" % prior_id} - } - - self.stub_url('GET', - ['roles', prior_id, 'implies'], - json=mock_response, - status_code=200) - - manager_result = self.manager.list(prior_id) - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(1, len(manager_result.implies)) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - def test_update(self): - # Update not supported for rule inferences - self.assertRaises(exceptions.MethodNotImplemented, self.manager.update) - - def test_find(self): - # Find not supported for rule inferences - self.assertRaises(exceptions.MethodNotImplemented, self.manager.find) - - def test_put(self): - # Put not supported for rule inferences - self.assertRaises(exceptions.MethodNotImplemented, self.manager.put) - - def test_list_params(self): - # Put not supported for rule inferences - self.skipTest("list params not supported by rule inferences") diff --git a/keystoneclient/tests/unit/v3/test_service_catalog.py b/keystoneclient/tests/unit/v3/test_service_catalog.py deleted file mode 100644 index bdd92ceb..00000000 --- a/keystoneclient/tests/unit/v3/test_service_catalog.py +++ /dev/null @@ -1,279 +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 keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient import exceptions -from keystoneclient.tests.unit import utils as test_utils -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -class ServiceCatalogTest(utils.TestCase): - def setUp(self): - super(ServiceCatalogTest, self).setUp() - self.AUTH_RESPONSE_BODY = client_fixtures.auth_response_body() - self.RESPONSE = test_utils.test_response( - headers=client_fixtures.AUTH_RESPONSE_HEADERS - ) - - self.north_endpoints = {'public': - 'http://glance.north.host/glanceapi/public', - 'internal': - 'http://glance.north.host/glanceapi/internal', - 'admin': - 'http://glance.north.host/glanceapi/admin'} - - self.south_endpoints = {'public': - 'http://glance.south.host/glanceapi/public', - 'internal': - 'http://glance.south.host/glanceapi/internal', - 'admin': - 'http://glance.south.host/glanceapi/admin'} - - def test_building_a_service_catalog(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - self.assertEqual(sc.url_for(service_type='compute'), - "https://compute.north.host/novapi/public") - self.assertEqual(sc.url_for(service_type='compute', - endpoint_type='internal'), - "https://compute.north.host/novapi/internal") - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, "region", - "South", service_type='compute') - - def test_service_catalog_endpoints(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - public_ep = sc.get_endpoints(service_type='compute', - endpoint_type='public') - self.assertEqual(public_ep['compute'][0]['region'], 'North') - self.assertEqual(public_ep['compute'][0]['url'], - "https://compute.north.host/novapi/public") - - def test_service_catalog_regions(self): - self.AUTH_RESPONSE_BODY['token']['region_name'] = "North" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', endpoint_type='public') - self.assertEqual(url, "http://glance.north.host/glanceapi/public") - - self.AUTH_RESPONSE_BODY['token']['region_name'] = "South" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - url = sc.url_for(service_type='image', endpoint_type='internal') - self.assertEqual(url, "http://glance.south.host/glanceapi/internal") - - def test_service_catalog_empty(self): - self.AUTH_RESPONSE_BODY['token']['catalog'] = [] - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - self.assertRaises(exceptions.EmptyCatalog, - auth_ref.service_catalog.url_for, - service_type='image', - endpoint_type='internalURL') - - def test_service_catalog_get_endpoints_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - endpoints = sc.get_endpoints(service_type='image', region_name='North') - self.assertEqual(len(endpoints), 1) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.north_endpoints[endpoint['interface']]) - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints), 1) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.south_endpoints[endpoint['interface']]) - - endpoints = sc.get_endpoints(service_type='compute') - self.assertEqual(len(endpoints['compute']), 3) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='North') - self.assertEqual(len(endpoints['compute']), 3) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='West') - self.assertEqual(len(endpoints['compute']), 0) - - def test_service_catalog_url_for_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', region_name='North') - self.assertEqual(url, self.north_endpoints['public']) - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, self.south_endpoints['public']) - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_type='image', region_name='West') - - def test_servcie_catalog_get_url_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - urls = sc.get_urls(service_type='image') - self.assertEqual(len(urls), 2) - - urls = sc.get_urls(service_type='image', region_name='North') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], self.north_endpoints['public']) - - urls = sc.get_urls(service_type='image', region_name='South') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], self.south_endpoints['public']) - - urls = sc.get_urls(service_type='image', region_name='West') - self.assertIsNone(urls) - - def test_service_catalog_param_overrides_body_region(self): - self.AUTH_RESPONSE_BODY['token']['region_name'] = "North" - # Passing region_name to service catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image') - self.assertEqual(url, self.north_endpoints['public']) - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, self.south_endpoints['public']) - - endpoints = sc.get_endpoints(service_type='image') - self.assertEqual(len(endpoints['image']), 3) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.north_endpoints[endpoint['interface']]) - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints['image']), 3) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.south_endpoints[endpoint['interface']]) - - def test_service_catalog_service_name(self): - auth_ref = access.AccessInfo.factory(resp=None, - body=self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_name='glance', endpoint_type='public', - service_type='image', region_name='North') - self.assertEqual('http://glance.north.host/glanceapi/public', url) - - url = sc.url_for(service_name='glance', endpoint_type='public', - service_type='image', region_name='South') - self.assertEqual('http://glance.south.host/glanceapi/public', url) - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_name='glance', service_type='compute') - - urls = sc.get_urls(service_type='image', service_name='glance', - endpoint_type='public') - - self.assertIn('http://glance.north.host/glanceapi/public', urls) - self.assertIn('http://glance.south.host/glanceapi/public', urls) - - urls = sc.get_urls(service_type='image', service_name='Servers', - endpoint_type='public') - - self.assertIsNone(urls) - - def test_service_catalog_without_name(self): - pr_auth_ref = access.AccessInfo.factory( - resp=None, - body=client_fixtures.project_scoped_token()) - pr_sc = pr_auth_ref.service_catalog - - # this will work because there are no service names on that token - url_ref = 'http://public.com:8774/v2/225da22d3ce34b15877ea70b2a575f58' - url = pr_sc.url_for(service_type='compute', service_name='NotExist', - endpoint_type='public') - self.assertEqual(url_ref, url) - - ab_auth_ref = access.AccessInfo.factory(resp=None, - body=self.AUTH_RESPONSE_BODY) - ab_sc = ab_auth_ref.service_catalog - - # this won't work because there is a name and it's not this one - self.assertRaises(exceptions.EndpointNotFound, ab_sc.url_for, - service_type='compute', service_name='NotExist', - endpoint_type='public') - - -class ServiceCatalogV3Test(ServiceCatalogTest): - - def test_building_a_service_catalog(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - self.assertEqual(sc.url_for(service_type='compute'), - 'https://compute.north.host/novapi/public') - self.assertEqual(sc.url_for(service_type='compute', - endpoint_type='internal'), - 'https://compute.north.host/novapi/internal') - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, 'region_id', - 'South', service_type='compute') - - def test_service_catalog_endpoints(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - public_ep = sc.get_endpoints(service_type='compute', - endpoint_type='public') - self.assertEqual(public_ep['compute'][0]['region_id'], 'North') - self.assertEqual(public_ep['compute'][0]['url'], - 'https://compute.north.host/novapi/public') - - def test_service_catalog_multiple_service_types(self): - token = fixture.V3Token() - token.set_project_scope() - - for i in range(3): - s = token.add_service('compute') - s.add_standard_endpoints(public='public-%d' % i, - admin='admin-%d' % i, - internal='internal-%d' % i, - region='region-%d' % i) - - auth_ref = access.AccessInfo.factory(resp=None, body=token) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='public') - - self.assertEqual(set(['public-0', 'public-1', 'public-2']), set(urls)) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='public', - region_name='region-1') - - self.assertEqual(('public-1', ), urls) diff --git a/keystoneclient/tests/unit/v3/test_services.py b/keystoneclient/tests/unit/v3/test_services.py deleted file mode 100644 index 9bda5dbb..00000000 --- a/keystoneclient/tests/unit/v3/test_services.py +++ /dev/null @@ -1,44 +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. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import services - - -class ServiceTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ServiceTests, self).setUp() - self.key = 'service' - self.collection_key = 'services' - self.model = services.Service - self.manager = self.client.services - - def new_ref(self, **kwargs): - kwargs = super(ServiceTests, self).new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def test_list_filter_name(self): - filter_name = uuid.uuid4().hex - expected_query = {'name': filter_name} - super(ServiceTests, self).test_list(expected_query=expected_query, - name=filter_name) - - def test_list_filter_type(self): - filter_type = uuid.uuid4().hex - expected_query = {'type': filter_type} - super(ServiceTests, self).test_list(expected_query=expected_query, - type=filter_type) diff --git a/keystoneclient/tests/unit/v3/test_simple_cert.py b/keystoneclient/tests/unit/v3/test_simple_cert.py deleted file mode 100644 index 1c4a245d..00000000 --- a/keystoneclient/tests/unit/v3/test_simple_cert.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 IBM Corp. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testresources - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -class SimpleCertTests(utils.ClientTestCase, testresources.ResourcedTestCase): - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_get_ca_certificate(self): - self.stub_url('GET', ['OS-SIMPLE-CERT', 'ca'], - headers={'Content-Type': 'application/x-pem-file'}, - text=self.examples.SIGNING_CA) - res = self.client.simple_cert.get_ca_certificates() - self.assertEqual(self.examples.SIGNING_CA, res) - - def test_get_certificates(self): - self.stub_url('GET', ['OS-SIMPLE-CERT', 'certificates'], - headers={'Content-Type': 'application/x-pem-file'}, - text=self.examples.SIGNING_CERT) - res = self.client.simple_cert.get_certificates() - self.assertEqual(self.examples.SIGNING_CERT, res) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v3/test_tokens.py b/keystoneclient/tests/unit/v3/test_tokens.py deleted file mode 100644 index 89b65f84..00000000 --- a/keystoneclient/tests/unit/v3/test_tokens.py +++ /dev/null @@ -1,163 +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. - -import uuid - -from keystoneauth1 import exceptions -import testresources - -from keystoneclient import access -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -class TokenTests(utils.ClientTestCase, testresources.ResourcedTestCase): - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_revoke_token_with_token_id(self): - token_id = uuid.uuid4().hex - self.stub_url('DELETE', ['/auth/tokens'], status_code=204) - self.client.tokens.revoke_token(token_id) - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - - def test_revoke_token_with_access_info_instance(self): - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - token = access.AccessInfoV3(token_id, token_ref['token']) - self.stub_url('DELETE', ['/auth/tokens'], status_code=204) - self.client.tokens.revoke_token(token) - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - - def test_get_revoked(self): - sample_revoked_response = {'signed': '-----BEGIN CMS-----\nMIIB...'} - self.stub_url('GET', ['auth', 'tokens', 'OS-PKI', 'revoked'], - json=sample_revoked_response) - resp = self.client.tokens.get_revoked() - self.assertQueryStringIs() - self.assertEqual(sample_revoked_response, resp) - - def test_get_revoked_audit_id_only(self): - # When get_revoked(audit_id_only=True) then ?audit_id_only is set on - # the request. - sample_revoked_response = { - 'revoked': [ - { - 'audit_id': uuid.uuid4().hex, - 'expires': '2016-01-21T15:53:52Z', - }, - ], - } - self.stub_url('GET', ['auth', 'tokens', 'OS-PKI', 'revoked'], - json=sample_revoked_response) - resp = self.client.tokens.get_revoked(audit_id_only=True) - self.assertQueryStringIs('audit_id_only') - self.assertEqual(sample_revoked_response, resp) - - def test_get_revoked_audit_id_only_positional_exc(self): - # When get_revoked(True) an exception is raised because this must be - # called with named parameter. - self.assertRaises(TypeError, self.client.tokens.get_revoked, True) - - def test_validate_token_with_token_id(self): - # Can validate a token passing a string token ID. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - token_data = self.client.tokens.get_token_data(token_id) - self.assertEqual(token_data, token_ref) - - access_info = self.client.tokens.validate(token_id) - - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - self.assertIsInstance(access_info, access.AccessInfoV3) - self.assertEqual(token_id, access_info.auth_token) - - def test_validate_token_with_access_info(self): - # Can validate a token passing an access info. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - token = access.AccessInfoV3(token_id, token_ref['token']) - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - access_info = self.client.tokens.validate(token) - - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - self.assertIsInstance(access_info, access.AccessInfoV3) - self.assertEqual(token_id, access_info.auth_token) - - def test_validate_token_invalid(self): - # When the token is invalid the server typically returns a 404. - token_id = uuid.uuid4().hex - self.stub_url('GET', ['auth', 'tokens'], status_code=404) - - self.assertRaises(exceptions.NotFound, - self.client.tokens.get_token_data, token_id) - self.assertRaises(exceptions.NotFound, - self.client.tokens.validate, token_id) - - def test_validate_token_catalog(self): - # Can validate a token and a catalog is requested by default. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - token_data = self.client.tokens.get_token_data(token_id) - self.assertQueryStringIs() - self.assertIn('catalog', token_data['token']) - - access_info = self.client.tokens.validate(token_id) - - self.assertQueryStringIs() - self.assertTrue(access_info.has_service_catalog()) - - def test_validate_token_nocatalog(self): - # Can validate a token and request no catalog. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_UNSCOPED] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - token_data = self.client.tokens.get_token_data(token_id) - self.assertQueryStringIs() - self.assertNotIn('catalog', token_data['token']) - - access_info = self.client.tokens.validate(token_id, - include_catalog=False) - - self.assertQueryStringIs('nocatalog') - self.assertFalse(access_info.has_service_catalog()) - - def test_validate_token_allow_expired(self): - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_UNSCOPED] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - self.client.tokens.validate(token_id) - self.assertQueryStringIs() - - self.client.tokens.validate(token_id, allow_expired=True) - self.assertQueryStringIs('allow_expired=1') - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v3/test_trusts.py b/keystoneclient/tests/unit/v3/test_trusts.py deleted file mode 100644 index 1c74ac9b..00000000 --- a/keystoneclient/tests/unit/v3/test_trusts.py +++ /dev/null @@ -1,128 +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. - -import uuid - -from oslo_utils import timeutils - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3.contrib import trusts - - -class TrustTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(TrustTests, self).setUp() - self.key = 'trust' - self.collection_key = 'trusts' - self.model = trusts.Trust - self.manager = self.client.trusts - self.path_prefix = 'OS-TRUST' - - def new_ref(self, **kwargs): - kwargs = super(TrustTests, self).new_ref(**kwargs) - kwargs.setdefault('project_id', uuid.uuid4().hex) - return kwargs - - def test_create(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - super(TrustTests, self).test_create(ref=ref) - - def test_create_limited_uses(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - ref['remaining_uses'] = 5 - super(TrustTests, self).test_create(ref=ref) - - def test_create_roles(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - req_ref = ref.copy() - req_ref.pop('id') - - # Note the TrustManager takes a list of role_names, and converts - # internally to the slightly odd list-of-dict API format, so we - # have to pass the expected request data to allow correct stubbing - ref['role_names'] = ['atestrole'] - req_ref['roles'] = [{'name': 'atestrole'}] - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_create_role_id_and_names(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - req_ref = ref.copy() - req_ref.pop('id') - - # Note the TrustManager takes a list of role_names, and converts - # internally to the slightly odd list-of-dict API format, so we - # have to pass the expected request data to allow correct stubbing - ref['role_names'] = ['atestrole'] - ref['role_ids'] = [uuid.uuid4().hex] - req_ref['roles'] = [{'name': 'atestrole'}, {'id': ref['role_ids'][0]}] - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_create_expires(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - ref['expires_at'] = timeutils.parse_isotime( - '2013-03-04T12:00:01.000000Z') - req_ref = ref.copy() - req_ref.pop('id') - - # Note the TrustManager takes a datetime.datetime object for - # expires_at, and converts it internally into an iso format datestamp - req_ref['expires_at'] = '2013-03-04T12:00:01.000000Z' - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_create_imp(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = True - super(TrustTests, self).test_create(ref=ref) - - def test_create_roles_imp(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = True - req_ref = ref.copy() - req_ref.pop('id') - ref['role_names'] = ['atestrole'] - req_ref['roles'] = [{'name': 'atestrole'}] - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_list_filter_trustor(self): - expected_query = {'trustor_user_id': '12345'} - super(TrustTests, self).test_list(expected_query=expected_query, - trustor_user='12345') - - def test_list_filter_trustee(self): - expected_query = {'trustee_user_id': '12345'} - super(TrustTests, self).test_list(expected_query=expected_query, - trustee_user='12345') - - def test_update(self): - # Update not supported for the OS-TRUST API - self.assertRaises(exceptions.MethodNotImplemented, self.manager.update) diff --git a/keystoneclient/tests/unit/v3/test_users.py b/keystoneclient/tests/unit/v3/test_users.py deleted file mode 100644 index e0a34461..00000000 --- a/keystoneclient/tests/unit/v3/test_users.py +++ /dev/null @@ -1,309 +0,0 @@ -# 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. - -import mock -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import users - - -class UserTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(UserTests, self).setUp() - self.key = 'user' - self.collection_key = 'users' - self.model = users.User - self.manager = self.client.users - - def new_ref(self, **kwargs): - kwargs = super(UserTests, self).new_ref(**kwargs) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('default_project_id', uuid.uuid4().hex) - return kwargs - - def test_add_user_to_group(self): - group_id = uuid.uuid4().hex - ref = self.new_ref() - self.stub_url('PUT', - ['groups', group_id, self.collection_key, ref['id']], - status_code=204) - - self.manager.add_to_group(user=ref['id'], group=group_id) - self.assertRaises(exceptions.ValidationError, - self.manager.remove_from_group, - user=ref['id'], - group=None) - - def test_list_users_in_group(self): - group_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['groups', group_id, self.collection_key], - entity=ref_list) - - returned_list = self.manager.list(group=group_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_check_user_in_group(self): - group_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['groups', group_id, self.collection_key, ref['id']], - status_code=204) - - self.manager.check_in_group(user=ref['id'], group=group_id) - - self.assertRaises(exceptions.ValidationError, - self.manager.check_in_group, - user=ref['id'], - group=None) - - def test_remove_user_from_group(self): - group_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['groups', group_id, self.collection_key, ref['id']], - status_code=204) - - self.manager.remove_from_group(user=ref['id'], group=group_id) - self.assertRaises(exceptions.ValidationError, - self.manager.remove_from_group, - user=ref['id'], - group=None) - - def test_create_doesnt_log_password(self): - password = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_entity('POST', [self.collection_key], - status_code=201, entity=ref) - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - param_ref['password'] = password - params = utils.parameterize(param_ref) - - self.manager.create(**params) - - self.assertNotIn(password, self.logger.output) - - def test_create_with_project(self): - # Can create a user with the deprecated project option rather than - # default_project_id. - self.deprecations.expect_deprecations() - ref = self.new_ref() - - self.stub_entity('POST', [self.collection_key], - status_code=201, entity=ref) - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - # Use deprecated project_id rather than new default_project_id. - param_ref['project_id'] = param_ref.pop('default_project_id') - params = utils.parameterize(param_ref) - - returned = self.manager.create(**params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_create_with_project_and_default_project(self): - # Can create a user with the deprecated project and default_project_id. - # The backend call should only pass the default_project_id. - self.deprecations.expect_deprecations() - - ref = self.new_ref() - - self.stub_entity('POST', - [self.collection_key], - status_code=201, entity=ref) - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - # Add the deprecated project_id in the call, the value will be ignored. - param_ref['project_id'] = 'project' - params = utils.parameterize(param_ref) - - returned = self.manager.create(**params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_update_doesnt_log_password(self): - password = uuid.uuid4().hex - ref = self.new_ref() - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - self.stub_entity('PATCH', - [self.collection_key, ref['id']], - status_code=200, entity=ref) - - param_ref['password'] = password - params = utils.parameterize(param_ref) - - self.manager.update(ref['id'], **params) - - self.assertNotIn(password, self.logger.output) - - def test_update_with_project(self): - # Can update a user with the deprecated project option rather than - # default_project_id. - self.deprecations.expect_deprecations() - - ref = self.new_ref() - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - self.stub_entity('PATCH', - [self.collection_key, ref['id']], - status_code=200, entity=ref) - - # Use deprecated project_id rather than new default_project_id. - param_ref['project_id'] = param_ref.pop('default_project_id') - params = utils.parameterize(param_ref) - - returned = self.manager.update(ref['id'], **params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_update_with_project_and_default_project(self, ref=None): - self.deprecations.expect_deprecations() - - ref = self.new_ref() - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - self.stub_entity('PATCH', - [self.collection_key, ref['id']], - status_code=200, entity=ref) - - # Add the deprecated project_id in the call, the value will be ignored. - param_ref['project_id'] = 'project' - params = utils.parameterize(param_ref) - - returned = self.manager.update(ref['id'], **params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_update_password(self): - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - - self.stub_url('POST', - [self.collection_key, self.TEST_USER_ID, 'password']) - self.client.user_id = self.TEST_USER_ID - self.manager.update_password(old_password, new_password) - - exp_req_body = { - 'user': { - 'password': new_password, 'original_password': old_password - } - } - - self.assertEqual( - '%s/users/%s/password' % (self.TEST_URL, self.TEST_USER_ID), - self.requests_mock.last_request.url) - self.assertRequestBodyIs(json=exp_req_body) - self.assertNotIn(old_password, self.logger.output) - self.assertNotIn(new_password, self.logger.output) - - def test_update_password_with_no_hardcoded_endpoint_filter(self): - # test to ensure the 'endpoint_filter' parameter is not being - # passed from the manager. Endpoint filtering should be done at - # the Session, not the individual managers. - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - expected_params = {'user': {'password': new_password, - 'original_password': old_password}} - user_password_update_path = '/users/%s/password' % self.TEST_USER_ID - - self.client.user_id = self.TEST_USER_ID - # NOTE(gyee): user manager subclass keystoneclient.base.Manager - # and utilize the _update() method in the base class to interface - # with the client session to perform the update. In the case, we - # just need to make sure the 'endpoint_filter' parameter is not - # there. - with mock.patch('keystoneclient.base.Manager._update') as m: - self.manager.update_password(old_password, new_password) - m.assert_called_with(user_password_update_path, expected_params, - method='POST', log=False) - - def test_update_password_with_bad_inputs(self): - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - - # users can't unset their password - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - old_password, None) - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - old_password, '') - - # users can't start with empty passwords - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - None, new_password) - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - '', new_password) - - # this wouldn't result in any change anyway - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - None, None) - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - '', '') - password = uuid.uuid4().hex - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - password, password) diff --git a/keystoneclient/tests/unit/v3/utils.py b/keystoneclient/tests/unit/v3/utils.py deleted file mode 100644 index d9cb5a47..00000000 --- a/keystoneclient/tests/unit/v3/utils.py +++ /dev/null @@ -1,373 +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. - -import uuid - -from six.moves.urllib import parse as urlparse - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils - - -def parameterize(ref): - """Rewrite attributes to match the kwarg naming convention in client. - - >>> parameterize({'project_id': 0}) - {'project': 0} - - """ - params = ref.copy() - for key in ref: - if key[-3:] == '_id': - params.setdefault(key[:-3], params.pop(key)) - return params - - -class UnauthenticatedTestCase(utils.TestCase): - """Class used as base for unauthenticated calls.""" - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v3') - - -class TestCase(UnauthenticatedTestCase): - - TEST_ADMIN_IDENTITY_ENDPOINT = "http://127.0.0.1:35357/v3" - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "url": "http://cdn.admin-nets.local:8774/v1.0/", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:8774/v1.0", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "interface": "admin" - }], - "type": "nova_compat" - }, { - "endpoints": [{ - "url": "http://nova/novapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://nova/novapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://nova/novapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "compute" - }, { - "endpoints": [{ - "url": "http://glance/glanceapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://glance/glanceapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://glance/glanceapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "internal" - }, { - "url": TEST_ADMIN_IDENTITY_ENDPOINT, - "region": "RegionOne", - "interface": "admin" - }], - "type": "identity" - }, { - "endpoints": [{ - "url": "http://swift/swiftapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://swift/swiftapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://swift/swiftapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "object-store" - }] - - def stub_auth(self, subject_token=None, **kwargs): - - if not subject_token: - subject_token = self.TEST_TOKEN - - try: - response_list = kwargs['response_list'] - except KeyError: - headers = kwargs.setdefault('headers', {}) - headers['X-Subject-Token'] = subject_token - else: - for resp in response_list: - headers = resp.setdefault('headers', {}) - headers['X-Subject-Token'] = subject_token - - self.stub_url('POST', ['auth', 'tokens'], **kwargs) - - -class ClientTestCase(utils.ClientTestCaseMixin, TestCase): - - ORIGINAL_CLIENT_TYPE = 'original' - KSC_SESSION_CLIENT_TYPE = 'ksc-session' - KSA_SESSION_CLIENT_TYPE = 'ksa-session' - - scenarios = [ - ( - ORIGINAL_CLIENT_TYPE, { - 'client_fixture_class': client_fixtures.OriginalV3, - 'client_type': ORIGINAL_CLIENT_TYPE - } - ), - ( - KSC_SESSION_CLIENT_TYPE, { - 'client_fixture_class': client_fixtures.KscSessionV3, - 'client_type': KSC_SESSION_CLIENT_TYPE - } - ), - ( - KSA_SESSION_CLIENT_TYPE, { - 'client_fixture_class': client_fixtures.KsaSessionV3, - 'client_type': KSA_SESSION_CLIENT_TYPE - } - ) - - ] - - @property - def is_original_client(self): - return self.client_type == self.ORIGINAL_CLIENT_TYPE - - @property - def is_session_client(self): - return self.client_type in (self.KSC_SESSION_CLIENT_TYPE, - self.KSA_SESSION_CLIENT_TYPE) - - -class CrudTests(object): - key = None - collection_key = None - model = None - manager = None - path_prefix = None - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault(uuid.uuid4().hex, uuid.uuid4().hex) - return kwargs - - def encode(self, entity): - if isinstance(entity, dict): - return {self.key: entity} - if isinstance(entity, list): - return {self.collection_key: entity} - raise NotImplementedError('Are you sure you want to encode that?') - - def stub_entity(self, method, parts=None, entity=None, id=None, **kwargs): - if entity: - entity = self.encode(entity) - kwargs['json'] = entity - - if not parts: - parts = [self.collection_key] - - if self.path_prefix: - parts.insert(0, self.path_prefix) - - if id: - if not parts: - parts = [] - - parts.append(id) - - self.stub_url(method, parts=parts, **kwargs) - - def assertEntityRequestBodyIs(self, entity): - self.assertRequestBodyIs(json=self.encode(entity)) - - def test_create(self, ref=None, req_ref=None): - ref = ref or self.new_ref() - manager_ref = ref.copy() - manager_ref.pop('id') - - # req_ref argument allows you to specify a different - # signature for the request when the manager does some - # conversion before doing the request (e.g. converting - # from datetime object to timestamp string) - if req_ref: - req_ref = req_ref.copy() - else: - req_ref = ref.copy() - req_ref.pop('id') - - self.stub_entity('POST', entity=req_ref, status_code=201) - - returned = self.manager.create(**parameterize(manager_ref)) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - # The entity created here may be used in other test cases - return returned - - def test_get(self, ref=None): - ref = ref or self.new_ref() - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id']) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - - def _get_expected_path(self, expected_path=None): - if not expected_path: - if self.path_prefix: - expected_path = 'v3/%s/%s' % (self.path_prefix, - self.collection_key) - else: - expected_path = 'v3/%s' % self.collection_key - - return expected_path - - def test_list_by_id(self, ref=None, **filter_kwargs): - """Test ``entities.list(id=x)`` being rewritten as ``GET /v3/entities/x``. - - This tests an edge case of each manager's list() implementation, to - ensure that it "does the right thing" when users call ``.list()`` - when they should have used ``.get()``. - - """ - if 'id' not in filter_kwargs: - ref = ref or self.new_ref() - filter_kwargs['id'] = ref['id'] - - self.assertRaises(TypeError, self.manager.list, **filter_kwargs) - - def test_list(self, ref_list=None, expected_path=None, - expected_query=None, **filter_kwargs): - ref_list = ref_list or [self.new_ref(), self.new_ref()] - expected_path = self._get_expected_path(expected_path) - - self.requests_mock.get(urlparse.urljoin(self.TEST_URL, expected_path), - json=self.encode(ref_list)) - - returned_list = self.manager.list(**filter_kwargs) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - qs_args = self.requests_mock.last_request.qs - qs_args_expected = expected_query or filter_kwargs - for key, value in qs_args_expected.items(): - self.assertIn(key, qs_args) - # The querystring value is a list. Note we convert the value to a - # string and lower, as the query string is always a string and the - # filter_kwargs may contain non-string values, for example a - # boolean, causing the comaprison to fail. - self.assertIn(str(value).lower(), qs_args[key]) - - # Also check that no query string args exist which are not expected - for key in qs_args: - self.assertIn(key, qs_args_expected) - - def test_list_params(self): - ref_list = [self.new_ref()] - filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} - expected_path = self._get_expected_path() - - self.requests_mock.get(urlparse.urljoin(self.TEST_URL, expected_path), - json=self.encode(ref_list)) - - self.manager.list(**filter_kwargs) - self.assertQueryStringContains(**filter_kwargs) - - def test_find(self, ref=None): - ref = ref or self.new_ref() - ref_list = [ref] - - self.stub_entity('GET', entity=ref_list) - - returned = self.manager.find(name=getattr(ref, 'name', None)) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - - if hasattr(ref, 'name'): - self.assertQueryStringIs('name=%s' % ref['name']) - else: - self.assertQueryStringIs('') - - def test_update(self, ref=None, req_ref=None): - ref = ref or self.new_ref() - - self.stub_entity('PATCH', id=ref['id'], entity=ref) - - # req_ref argument allows you to specify a different - # signature for the request when the manager does some - # conversion before doing the request (e.g. converting - # from datetime object to timestamp string) - if req_ref: - req_ref = req_ref.copy() - else: - req_ref = ref.copy() - req_ref.pop('id') - - returned = self.manager.update(ref['id'], **parameterize(req_ref)) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_delete(self, ref=None): - ref = ref or self.new_ref() - - self.stub_entity('DELETE', id=ref['id'], status_code=204) - self.manager.delete(ref['id']) diff --git a/keystoneclient/utils.py b/keystoneclient/utils.py deleted file mode 100644 index 8e8dd7c7..00000000 --- a/keystoneclient/utils.py +++ /dev/null @@ -1,126 +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. - -import getpass -import hashlib -import sys - -from keystoneauth1 import exceptions as ksa_exceptions -from oslo_utils import timeutils -# NOTE(stevemar): do not remove positional. We need this to stay for a while -# since versions of auth_token require it here. -from positional import positional # noqa -import six - -from keystoneclient import exceptions as ksc_exceptions - - -def find_resource(manager, name_or_id): - """Helper for the _find_* methods.""" - # first try the entity as a string - try: - return manager.get(name_or_id) - except (ksa_exceptions.NotFound): # nosec(cjschaef): try to find - # 'name_or_id' as a six.binary_type instead - pass - - # finally try to find entity by name - try: - if isinstance(name_or_id, six.binary_type): - name_or_id = name_or_id.decode('utf-8', 'strict') - return manager.find(name=name_or_id) - except ksa_exceptions.NotFound: - msg = ("No %s with a name or ID of '%s' exists." % - (manager.resource_class.__name__.lower(), name_or_id)) - raise ksc_exceptions.CommandError(msg) - except ksc_exceptions.NoUniqueMatch: - msg = ("Multiple %s matches found for '%s', use an ID to be more" - " specific." % (manager.resource_class.__name__.lower(), - name_or_id)) - raise ksc_exceptions.CommandError(msg) - - -def hash_signed_token(signed_text, mode='md5'): - hash_ = hashlib.new(mode) - hash_.update(signed_text) - return hash_.hexdigest() - - -def prompt_user_password(): - """Prompt user for a password. - - Prompt for a password if stdin is a tty. - """ - password = None - - # If stdin is a tty, try prompting for the password - if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty(): - # Check for Ctl-D - try: - password = getpass.getpass('Password: ') - except EOFError: # nosec(cjschaef): return password, which is None if - # password was not found - pass - - return password - - -def prompt_for_password(): - """Prompt user for password if not provided. - - Prompt is used so the password doesn't show up in the - bash history. - """ - if not (hasattr(sys.stdin, 'isatty') and sys.stdin.isatty()): - # nothing to do - return - - while True: - try: - new_passwd = getpass.getpass('New Password: ') - rep_passwd = getpass.getpass('Repeat New Password: ') - if new_passwd == rep_passwd: - return new_passwd - except EOFError: - return - - -_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' -_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' - - -def isotime(at=None, subsecond=False): - """Stringify time in ISO 8601 format.""" - # Python provides a similar instance method for datetime.datetime objects - # called isoformat(). The format of the strings generated by isoformat() - # have a couple of problems: - # 1) The strings generated by isotime are used in tokens and other public - # APIs that we can't change without a deprecation period. The strings - # generated by isoformat are not the same format, so we can't just - # change to it. - # 2) The strings generated by isoformat do not include the microseconds if - # the value happens to be 0. This will likely show up as random failures - # as parsers may be written to always expect microseconds, and it will - # parse correctly most of the time. - if not at: - at = timeutils.utcnow() - st = at.strftime(_ISO8601_TIME_FORMAT - if not subsecond - else _ISO8601_TIME_FORMAT_SUBSECOND) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - st += ('Z' if tz == 'UTC' else tz) - return st - - -def strtime(at=None): - at = at or timeutils.utcnow() - return at.strftime(timeutils.PERFECT_TIME_FORMAT) diff --git a/keystoneclient/v2_0/__init__.py b/keystoneclient/v2_0/__init__.py deleted file mode 100644 index 23382fea..00000000 --- a/keystoneclient/v2_0/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from keystoneclient.v2_0.client import Client # noqa - - -__all__ = ( - 'client', -) diff --git a/keystoneclient/v2_0/certificates.py b/keystoneclient/v2_0/certificates.py deleted file mode 100644 index 2c69dfb3..00000000 --- a/keystoneclient/v2_0/certificates.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 IBM Corp. -# 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. - - -class CertificatesManager(object): - """Manager for certificates.""" - - def __init__(self, client): - self._client = client - - def get_ca_certificate(self): - """Get CA certificate. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/certificates/ca', authenticated=False) - return resp.text - - def get_signing_certificate(self): - """Get signing certificate. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/certificates/signing', - authenticated=False) - return resp.text diff --git a/keystoneclient/v2_0/client.py b/keystoneclient/v2_0/client.py deleted file mode 100644 index 904f7693..00000000 --- a/keystoneclient/v2_0/client.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import warnings - -from keystoneclient.auth.identity import v2 as v2_auth -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient.i18n import _ -from keystoneclient.v2_0 import certificates -from keystoneclient.v2_0 import ec2 -from keystoneclient.v2_0 import endpoints -from keystoneclient.v2_0 import extensions -from keystoneclient.v2_0 import roles -from keystoneclient.v2_0 import services -from keystoneclient.v2_0 import tenants -from keystoneclient.v2_0 import tokens -from keystoneclient.v2_0 import users - - -_logger = logging.getLogger(__name__) - - -class Client(httpclient.HTTPClient): - """Client for the OpenStack Keystone v2.0 API. - - :param string username: Username for authentication. (optional) - :param string password: Password for authentication. (optional) - :param string token: Token for authentication. (optional) - :param string tenant_id: Tenant id. (optional) - :param string tenant_name: Tenant name. (optional) - :param string auth_url: Keystone service endpoint for authorization. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - :param string endpoint: A user-supplied endpoint URL for the keystone - service. Lazy-authentication is possible for API - service calls if endpoint is set at - instantiation.(optional) - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - :param string original_ip: The original IP of the requesting user - which will be sent to Keystone in a - 'Forwarded' header. (optional) - :param string cert: Path to the Privacy Enhanced Mail (PEM) file which - contains the corresponding X.509 client certificate - needed to established two-way SSL connection with - the identity service. (optional) - :param string key: Path to the Privacy Enhanced Mail (PEM) file which - contains the unencrypted client private key needed - to established two-way SSL connection with the - identity service. (optional) - :param string cacert: Path to the Privacy Enhanced Mail (PEM) file which - contains the trusted authority X.509 certificates - needed to established SSL connection with the - identity service. (optional) - :param boolean insecure: Does not perform X.509 certificate validation - when establishing SSL connection with identity - service. default: False (optional) - :param dict auth_ref: To allow for consumers of the client to manage their - own caching strategy, you may initialize a client - with a previously captured auth_reference (token) - :param boolean debug: Enables debug logging of all request and responses - to keystone. default False (option) - - .. warning:: - - If debug is enabled, it may show passwords in plain text as a part of - its output. - - .. warning:: - - Constructing an instance of this class without a session is - deprecated as of the 1.7.0 release and will be removed in the - 2.0.0 release. - - The client can be created and used like a user or in a strictly - bootstrap mode. Normal operation expects a username, password, auth_url, - and tenant_name or id to be provided. Other values will be lazily loaded - as needed from the service catalog. - - Example:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> auth = v2.Password(auth_url=KEYSTONE_URL, - ... username=USER, - ... password=PASS, - ... tenant_name=TENANT_NAME) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.tenants.list() - ... - >>> user = keystone.users.get(USER_ID) - >>> user.delete() - - Once authenticated, you can store and attempt to re-use the - authenticated token. the auth_ref property on the client - returns as a dictionary-like-object so that you can export and - cache it, re-using it when initiating another client:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> auth = v2.Password(auth_url=KEYSTONE_URL, - ... username=USER, - ... password=PASS, - ... tenant_name=TENANT_NAME) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> auth_ref = keystone.auth_ref - >>> # pickle or whatever you like here - >>> new_client = client.Client(auth_ref=auth_ref) - - Alternatively, you can provide the administrative token configured in - keystone and an endpoint to communicate with directly. See - (``admin_token`` in ``keystone.conf``) In this case, authenticate() - is not needed, and no service catalog will be loaded. - - Example:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> auth = v2.Token(auth_url='http://localhost:35357/v2.0', - ... token='12345secret7890') - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.tenants.list() - - """ - - version = 'v2.0' - - def __init__(self, **kwargs): - """Initialize a new client for the Keystone v2.0 API.""" - if not kwargs.get('session'): - warnings.warn( - 'Constructing an instance of the ' - 'keystoneclient.v2_0.client.Client class without a session is ' - 'deprecated as of the 1.7.0 release and may be removed in ' - 'the 2.0.0 release.', DeprecationWarning) - - super(Client, self).__init__(**kwargs) - - self.certificates = certificates.CertificatesManager(self._adapter) - self.endpoints = endpoints.EndpointManager(self._adapter) - self.extensions = extensions.ExtensionManager(self._adapter) - self.roles = roles.RoleManager(self._adapter) - self.services = services.ServiceManager(self._adapter) - self.tokens = tokens.TokenManager(self._adapter) - self.users = users.UserManager(self._adapter, self.roles) - - self.tenants = tenants.TenantManager(self._adapter, - self.roles, self.users) - - # extensions - self.ec2 = ec2.CredentialsManager(self._adapter) - - # DEPRECATED: if session is passed then we go to the new behaviour of - # authenticating on the first required call. - if not kwargs.get('session') and self.management_url is None: - self.authenticate() - - def get_raw_token_from_identity_service(self, auth_url, username=None, - password=None, tenant_name=None, - tenant_id=None, token=None, - project_name=None, project_id=None, - trust_id=None, - **kwargs): - """Authenticate against the v2 Identity API. - - If a token is provided it will be used in preference over username and - password. - - :returns: access.AccessInfo if authentication was successful. - :raises keystoneclient.exceptions.AuthorizationFailure: if unable to - authenticate or validate the existing authorization token - """ - try: - if auth_url is None: - raise ValueError(_("Cannot authenticate without an auth_url")) - - new_kwargs = {'trust_id': trust_id, - 'tenant_id': project_id or tenant_id, - 'tenant_name': project_name or tenant_name} - - if token: - plugin = v2_auth.Token(auth_url, token, **new_kwargs) - elif username and password: - plugin = v2_auth.Password(auth_url, username, password, - **new_kwargs) - else: - msg = _('A username and password or token is required.') - raise exceptions.AuthorizationFailure(msg) - - return plugin.get_auth_ref(self.session) - except (exceptions.AuthorizationFailure, exceptions.Unauthorized): - _logger.debug("Authorization Failed.") - raise - except exceptions.EndpointNotFound: - msg = ( - _('There was no suitable authentication url for this request')) - raise exceptions.AuthorizationFailure(msg) - except Exception as e: - raise exceptions.AuthorizationFailure( - _("Authorization Failed: %s") % e) diff --git a/keystoneclient/v2_0/ec2.py b/keystoneclient/v2_0/ec2.py deleted file mode 100644 index 0abe98b0..00000000 --- a/keystoneclient/v2_0/ec2.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# All Rights Reserved. -# -# 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 import base - - -class EC2(base.Resource): - def __repr__(self): - """Return string representation of EC2 resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - -class CredentialsManager(base.ManagerWithFind): - resource_class = EC2 - - def create(self, user_id, tenant_id): - """Create a new access/secret pair for the user/tenant pair. - - :rtype: object of type :class:`EC2` - """ - params = {'tenant_id': tenant_id} - - return self._post('/users/%s/credentials/OS-EC2' % user_id, - params, "credential") - - def list(self, user_id): - """Get a list of access/secret pairs for a user_id. - - :rtype: list of :class:`EC2` - """ - return self._list("/users/%s/credentials/OS-EC2" % user_id, - "credentials") - - def get(self, user_id, access): - """Get the access/secret pair for a given access key. - - :rtype: object of type :class:`EC2` - """ - return self._get("/users/%s/credentials/OS-EC2/%s" % - (user_id, base.getid(access)), "credential") - - def delete(self, user_id, access): - """Delete an access/secret pair for a user.""" - return self._delete("/users/%s/credentials/OS-EC2/%s" % - (user_id, base.getid(access))) diff --git a/keystoneclient/v2_0/endpoints.py b/keystoneclient/v2_0/endpoints.py deleted file mode 100644 index 13ac399d..00000000 --- a/keystoneclient/v2_0/endpoints.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2012 Canonical Ltd. -# All Rights Reserved. -# -# 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 import base - - -class Endpoint(base.Resource): - """Represents a Keystone endpoint.""" - - def __repr__(self): - """Return string representation of endpoint resource information.""" - return "" % self._info - - -class EndpointManager(base.ManagerWithFind): - """Manager class for manipulating Keystone endpoints.""" - - resource_class = Endpoint - - def list(self): - """List all available endpoints.""" - return self._list('/endpoints', 'endpoints') - - def create(self, region, service_id, publicurl, adminurl=None, - internalurl=None): - """Create a new endpoint.""" - body = {'endpoint': {'region': region, - 'service_id': service_id, - 'publicurl': publicurl, - 'adminurl': adminurl, - 'internalurl': internalurl}} - return self._post('/endpoints', body, 'endpoint') - - def delete(self, id): - """Delete an endpoint.""" - return self._delete('/endpoints/%s' % id) diff --git a/keystoneclient/v2_0/extensions.py b/keystoneclient/v2_0/extensions.py deleted file mode 100644 index f1c40270..00000000 --- a/keystoneclient/v2_0/extensions.py +++ /dev/null @@ -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 import base - - -class Extension(base.Resource): - """Represents an Identity API extension.""" - - def __repr__(self): - """Return string representation of extension resource information.""" - return "" % self._info - - -class ExtensionManager(base.ManagerWithFind): - """Manager class for listing Identity API extensions.""" - - resource_class = Extension - - def list(self): - """List all available extensions.""" - return self._list('/extensions', 'extensions') diff --git a/keystoneclient/v2_0/roles.py b/keystoneclient/v2_0/roles.py deleted file mode 100644 index b9180844..00000000 --- a/keystoneclient/v2_0/roles.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 import base - - -class Role(base.Resource): - """Represents a Keystone role.""" - - def __repr__(self): - """Return string representation of role resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - -class RoleManager(base.ManagerWithFind): - """Manager class for manipulating Keystone roles.""" - - resource_class = Role - - def get(self, role): - return self._get("/OS-KSADM/roles/%s" % base.getid(role), "role") - - def create(self, name): - """Create a role.""" - params = {"role": {"name": name}} - return self._post('/OS-KSADM/roles', params, "role") - - def delete(self, role): - """Delete a role.""" - return self._delete("/OS-KSADM/roles/%s" % base.getid(role)) - - def list(self): - """List all available roles.""" - return self._list("/OS-KSADM/roles", "roles") - - def roles_for_user(self, user, tenant=None): - user_id = base.getid(user) - if tenant: - tenant_id = base.getid(tenant) - route = "/tenants/%s/users/%s/roles" - return self._list(route % (tenant_id, user_id), "roles") - else: - return self._list("/users/%s/roles" % user_id, "roles") - - def add_user_role(self, user, role, tenant=None): - """Add a role to a user. - - If tenant is specified, the role is added just for that tenant, - otherwise the role is added globally. - """ - user_id = base.getid(user) - role_id = base.getid(role) - if tenant: - route = "/tenants/%s/users/%s/roles/OS-KSADM/%s" - params = (base.getid(tenant), user_id, role_id) - return self._update(route % params, None, "role") - else: - route = "/users/%s/roles/OS-KSADM/%s" - return self._update(route % (user_id, role_id), None, "roles") - - def remove_user_role(self, user, role, tenant=None): - """Remove a role from a user. - - If tenant is specified, the role is removed just for that tenant, - otherwise the role is removed from the user's global roles. - """ - user_id = base.getid(user) - role_id = base.getid(role) - if tenant: - route = "/tenants/%s/users/%s/roles/OS-KSADM/%s" - params = (base.getid(tenant), user_id, role_id) - return self._delete(route % params) - else: - route = "/users/%s/roles/OS-KSADM/%s" - return self._delete(route % (user_id, role_id)) diff --git a/keystoneclient/v2_0/services.py b/keystoneclient/v2_0/services.py deleted file mode 100644 index 8f20b4da..00000000 --- a/keystoneclient/v2_0/services.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 import base - - -class Service(base.Resource): - """Represents a Keystone service.""" - - def __repr__(self): - """Return string representation of service resource information.""" - return "" % self._info - - -class ServiceManager(base.ManagerWithFind): - """Manager class for manipulating Keystone services.""" - - resource_class = Service - - def list(self): - """List available services.""" - return self._list("/OS-KSADM/services", "OS-KSADM:services") - - def get(self, id): - """Retrieve a service by id.""" - return self._get("/OS-KSADM/services/%s" % id, "OS-KSADM:service") - - def create(self, name, service_type, description=None): - """Create a new service.""" - body = {"OS-KSADM:service": {'name': name, - 'type': service_type, - 'description': description}} - return self._post("/OS-KSADM/services", body, "OS-KSADM:service") - - def delete(self, id): - """Delete a service.""" - return self._delete("/OS-KSADM/services/%s" % id) diff --git a/keystoneclient/v2_0/tenants.py b/keystoneclient/v2_0/tenants.py deleted file mode 100644 index 1b43990d..00000000 --- a/keystoneclient/v2_0/tenants.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 keystoneauth1 import plugin -from six.moves import urllib - -from keystoneclient import base -from keystoneclient import exceptions - - -class Tenant(base.Resource): - """Represents a Keystone tenant. - - Attributes: - * id: a uuid that identifies the tenant - * name: tenant name - * description: tenant description - * enabled: boolean to indicate if tenant is enabled - - """ - - def __repr__(self): - """Return string representation of tenant resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - def update(self, name=None, description=None, enabled=None): - # Preserve the existing settings; keystone legacy resets these? - new_name = name if name else self.name - if description is not None: - new_description = description - else: - new_description = self.description - new_enabled = enabled if enabled is not None else self.enabled - - try: - retval = self.manager.update(self.id, tenant_name=new_name, - description=new_description, - enabled=new_enabled) - self = retval - except Exception: - retval = None - return retval - - def add_user(self, user, role): - return self.manager.role_manager.add_user_role(base.getid(user), - base.getid(role), - self.id) - - def remove_user(self, user, role): - return self.manager.role_manager.remove_user_role(base.getid(user), - base.getid(role), - self.id) - - def list_users(self): - return self.manager.list_users(self.id) - - -class TenantManager(base.ManagerWithFind): - """Manager class for manipulating Keystone tenants.""" - - resource_class = Tenant - - def __init__(self, client, role_manager, user_manager): - super(TenantManager, self).__init__(client) - self.role_manager = role_manager - self.user_manager = user_manager - - def get(self, tenant_id): - return self._get("/tenants/%s" % tenant_id, "tenant") - - def create(self, tenant_name, description=None, enabled=True, **kwargs): - """Create a new tenant.""" - params = {"tenant": {"name": tenant_name, - "description": description, - "enabled": enabled}} - - # Allow Extras Passthru and ensure we don't clobber primary arguments. - for k, v in kwargs.items(): - if k not in params['tenant']: - params['tenant'][k] = v - - return self._post('/tenants', params, "tenant") - - def list(self, limit=None, marker=None): - """Get a list of tenants. - - :param integer limit: maximum number to return. (optional) - :param string marker: use when specifying a limit and making - multiple calls for querying. (optional) - - :rtype: list of :class:`Tenant` - - """ - params = {} - if limit: - params['limit'] = limit - if marker: - params['marker'] = marker - - query = "" - if params: - query = "?" + urllib.parse.urlencode(params) - - # NOTE(jamielennox): try doing a regular admin query first. If there is - # no endpoint that can satisfy the request (eg an unscoped token) then - # issue it against the auth_url. - try: - tenant_list = self._list('/tenants%s' % query, 'tenants') - except exceptions.EndpointNotFound: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - tenant_list = self._list('/tenants%s' % query, 'tenants', - endpoint_filter=endpoint_filter) - - return tenant_list - - def update(self, tenant_id, tenant_name=None, description=None, - enabled=None, **kwargs): - """Update a tenant with a new name and description.""" - body = {"tenant": {'id': tenant_id}} - if tenant_name is not None: - body['tenant']['name'] = tenant_name - if enabled is not None: - body['tenant']['enabled'] = enabled - if description is not None: - body['tenant']['description'] = description - - # Allow Extras Passthru and ensure we don't clobber primary arguments. - for k, v in kwargs.items(): - if k not in body['tenant']: - body['tenant'][k] = v - - # Keystone's API uses a POST rather than a PUT here. - return self._post("/tenants/%s" % tenant_id, body, "tenant") - - def delete(self, tenant): - """Delete a tenant.""" - return self._delete("/tenants/%s" % (base.getid(tenant))) - - def list_users(self, tenant): - """List users for a tenant.""" - return self.user_manager.list(base.getid(tenant)) - - def add_user(self, tenant, user, role): - """Add a user to a tenant with the given role.""" - return self.role_manager.add_user_role(base.getid(user), - base.getid(role), - base.getid(tenant)) - - def remove_user(self, tenant, user, role): - """Remove the specified role from the user on the tenant.""" - return self.role_manager.remove_user_role(base.getid(user), - base.getid(role), - base.getid(tenant)) diff --git a/keystoneclient/v2_0/tokens.py b/keystoneclient/v2_0/tokens.py deleted file mode 100644 index 8e647966..00000000 --- a/keystoneclient/v2_0/tokens.py +++ /dev/null @@ -1,127 +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 keystoneauth1 import exceptions -from keystoneauth1 import plugin -from positional import positional - -from keystoneclient import access -from keystoneclient import base -from keystoneclient.i18n import _ - - -class Token(base.Resource): - def __repr__(self): - """Return string representation of resource information.""" - return "" % self._info - - @property - def id(self): - return self._info['token']['id'] - - @property - def expires(self): - return self._info['token']['expires'] - - @property - def tenant(self): - return self._info['token'].get('tenant') - - -class TokenManager(base.Manager): - resource_class = Token - - @positional(enforcement=positional.WARN) - def authenticate(self, username=None, tenant_id=None, tenant_name=None, - password=None, token=None, return_raw=False): - if token: - params = {"auth": {"token": {"id": token}}} - elif username and password: - params = {"auth": {"passwordCredentials": {"username": username, - "password": password}}} - else: - raise ValueError( - _('A username and password or token is required.')) - if tenant_id: - params['auth']['tenantId'] = tenant_id - elif tenant_name: - params['auth']['tenantName'] = tenant_name - - args = ['/tokens', params, 'access'] - kwargs = {'return_raw': return_raw, 'log': False} - - # NOTE(jamielennox): try doing a regular admin query first. If there is - # no endpoint that can satisfy the request (eg an unscoped token) then - # issue it against the auth_url. - try: - token_ref = self._post(*args, **kwargs) - except exceptions.EndpointNotFound: - kwargs['endpoint_filter'] = {'interface': plugin.AUTH_INTERFACE} - token_ref = self._post(*args, **kwargs) - - return token_ref - - def delete(self, token): - return self._delete("/tokens/%s" % base.getid(token)) - - def endpoints(self, token): - return self._get("/tokens/%s/endpoints" % base.getid(token), "token") - - def validate(self, token): - """Validate a token. - - :param token: Token to be validated. - - :rtype: :py:class:`.Token` - - """ - return self._get('/tokens/%s' % base.getid(token), 'access') - - def get_token_data(self, token): - """Fetch the data about a token from the identity server. - - :param str token: The token id. - - :rtype: dict - """ - url = '/tokens/%s' % token - resp, body = self.client.get(url) - return body - - def validate_access_info(self, token): - """Validate a token. - - :param token: Token to be validated. This can be an instance of - :py:class:`keystoneclient.access.AccessInfo` or a string - token_id. - - :rtype: :py:class:`keystoneclient.access.AccessInfoV2` - - """ - def calc_id(token): - if isinstance(token, access.AccessInfo): - return token.auth_token - return base.getid(token) - - token_id = calc_id(token) - body = self.get_token_data(token_id) - return access.AccessInfo.factory(auth_token=token_id, body=body) - - def get_revoked(self): - """Return the revoked tokens response. - - The response will be a dict containing 'signed' which is a CMS-encoded - document. - - """ - resp, body = self.client.get('/tokens/revoked') - return body diff --git a/keystoneclient/v2_0/users.py b/keystoneclient/v2_0/users.py deleted file mode 100644 index f663626a..00000000 --- a/keystoneclient/v2_0/users.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 six.moves import urllib - -from keystoneclient import base - - -class User(base.Resource): - """Represents a Keystone user.""" - - def __repr__(self): - """Return string representation of user resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - def list_roles(self, tenant=None): - return self.manager.list_roles(self.id, base.getid(tenant)) - - -class UserManager(base.ManagerWithFind): - """Manager class for manipulating Keystone users.""" - - resource_class = User - - def __init__(self, client, role_manager): - super(UserManager, self).__init__(client) - self.role_manager = role_manager - - def get(self, user): - return self._get("/users/%s" % base.getid(user), "user") - - def update(self, user, **kwargs): - """Update user data. - - Supported arguments include ``name``, ``email``, and ``enabled``. - """ - # FIXME(gabriel): "tenantId" seems to be accepted by the API but - # fails to actually update the default tenant. - params = {"user": kwargs} - url = "/users/%s" % base.getid(user) - return self._update(url, params, "user") - - def update_enabled(self, user, enabled): - """Update enabled-ness.""" - params = {"user": {"enabled": enabled}} - - self._update("/users/%s/OS-KSADM/enabled" % base.getid(user), params, - "user") - - def update_password(self, user, password): - """Update password.""" - params = {"user": {"password": password}} - - return self._update("/users/%s/OS-KSADM/password" % base.getid(user), - params, "user", log=False) - - def update_own_password(self, origpasswd, passwd): - """Update password.""" - params = {"user": {"password": passwd, - "original_password": origpasswd}} - - return self._update("/OS-KSCRUD/users/%s" % self.client.user_id, - params, - response_key="access", - method="PATCH", - endpoint_filter={'interface': 'public'}, - log=False) - - def update_tenant(self, user, tenant): - """Update default tenant.""" - params = {"user": {"tenantId": base.getid(tenant)}} - - # FIXME(ja): seems like a bad url - default tenant is an attribute - # not a subresource!??? - return self._update("/users/%s/OS-KSADM/tenant" % base.getid(user), - params, "user") - - def create(self, name, password=None, email=None, - tenant_id=None, enabled=True): - """Create a user.""" - params = {"user": {"name": name, - "password": password, - "tenantId": tenant_id, - "email": email, - "enabled": enabled}} - return self._post('/users', params, "user", log=not bool(password)) - - def delete(self, user): - """Delete a user.""" - return self._delete("/users/%s" % base.getid(user)) - - def list(self, tenant_id=None, limit=None, marker=None): - """Get a list of users (optionally limited to a tenant). - - :rtype: list of :class:`User` - """ - params = {} - if limit: - params['limit'] = int(limit) - if marker: - params['marker'] = marker - - query = "" - if params: - query = "?" + urllib.parse.urlencode(params) - - if not tenant_id: - return self._list("/users%s" % query, "users") - else: - return self._list("/tenants/%s/users%s" % (tenant_id, query), - "users") - - def list_roles(self, user, tenant=None): - return self.role_manager.roles_for_user(base.getid(user), - base.getid(tenant)) diff --git a/keystoneclient/v3/__init__.py b/keystoneclient/v3/__init__.py deleted file mode 100644 index fcb00e06..00000000 --- a/keystoneclient/v3/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ - -from keystoneclient.v3.client import Client # noqa - - -__all__ = ( - 'client', -) diff --git a/keystoneclient/v3/auth.py b/keystoneclient/v3/auth.py deleted file mode 100644 index 6b8d6e9d..00000000 --- a/keystoneclient/v3/auth.py +++ /dev/null @@ -1,69 +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 keystoneauth1 import exceptions -from keystoneauth1 import plugin - -from keystoneclient import base -from keystoneclient.v3 import domains -from keystoneclient.v3 import projects - - -Domain = domains.Domain -Project = projects.Project - - -class AuthManager(base.Manager): - """Retrieve auth context specific information. - - The information returned by the auth routes is entirely dependent on the - authentication information provided by the user. - """ - - _PROJECTS_URL = '/auth/projects' - _DOMAINS_URL = '/auth/domains' - - def projects(self): - """List projects that the specified token can be rescoped to. - - :returns: a list of projects. - :rtype: list of :class:`keystoneclient.v3.projects.Project` - - """ - try: - return self._list(self._PROJECTS_URL, - 'projects', - obj_class=Project) - except exceptions.EndpointNotFound: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - return self._list(self._PROJECTS_URL, - 'projects', - obj_class=Project, - endpoint_filter=endpoint_filter) - - def domains(self): - """List Domains that the specified token can be rescoped to. - - :returns: a list of domains. - :rtype: list of :class:`keystoneclient.v3.domains.Domain`. - - """ - try: - return self._list(self._DOMAINS_URL, - 'domains', - obj_class=Domain) - except exceptions.EndpointNotFound: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - return self._list(self._DOMAINS_URL, - 'domains', - obj_class=Domain, - endpoint_filter=endpoint_filter) diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py deleted file mode 100644 index 2ca180a7..00000000 --- a/keystoneclient/v3/client.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import warnings - -from oslo_serialization import jsonutils - -from keystoneclient.auth.identity import v3 as v3_auth -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient.i18n import _ -from keystoneclient.v3 import auth -from keystoneclient.v3.contrib import endpoint_filter -from keystoneclient.v3.contrib import endpoint_policy -from keystoneclient.v3.contrib import federation -from keystoneclient.v3.contrib import oauth1 -from keystoneclient.v3.contrib import simple_cert -from keystoneclient.v3.contrib import trusts -from keystoneclient.v3 import credentials -from keystoneclient.v3 import domain_configs -from keystoneclient.v3 import domains -from keystoneclient.v3 import ec2 -from keystoneclient.v3 import endpoint_groups -from keystoneclient.v3 import endpoints -from keystoneclient.v3 import groups -from keystoneclient.v3 import policies -from keystoneclient.v3 import projects -from keystoneclient.v3 import regions -from keystoneclient.v3 import role_assignments -from keystoneclient.v3 import roles -from keystoneclient.v3 import services -from keystoneclient.v3 import tokens -from keystoneclient.v3 import users - - -_logger = logging.getLogger(__name__) - - -class Client(httpclient.HTTPClient): - r"""Client for the OpenStack Identity API v3. - - :param session: Session for requests. (optional) - :type session: keystoneauth1.session.Session - :param string user_id: User ID for authentication. (optional) - :param string username: Username for authentication. (optional) - :param string user_domain_id: User's domain ID for authentication. - (optional) - :param string user_domain_name: User's domain name for authentication. - (optional) - :param string password: Password for authentication. (optional) - :param string token: Token for authentication. (optional) - :param string domain_id: Domain ID for domain scoping. (optional) - :param string domain_name: Domain name for domain scoping. (optional) - :param string project_id: Project ID for project scoping. (optional) - :param string project_name: Project name for project scoping. (optional) - :param string project_domain_id: Project's domain ID for project - scoping. (optional) - :param string project_domain_name: Project's domain name for project - scoping. (optional) - :param string tenant_name: Tenant name. (optional) - The tenant_name keyword argument is deprecated - as of the 1.7.0 release in favor of project_name - and may be removed in the 2.0.0 release. - :param string tenant_id: Tenant id. (optional) - The tenant_id keyword argument is deprecated as of - the 1.7.0 release in favor of project_id and may - be removed in the 2.0.0 release. - :param string auth_url: Identity service endpoint for authorization. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - :param string endpoint: A user-supplied endpoint URL for the identity - service. Lazy-authentication is possible for API - service calls if endpoint is set at - instantiation. (optional) - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - - .. warning:: - - Constructing an instance of this class without a session is - deprecated as of the 1.7.0 release and will be removed in the - 2.0.0 release. - - Example:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - >>> auth = v3.Password(user_domain_name=DOMAIN_NAME, - ... username=USER, - ... password=PASS, - ... project_domain_name=PROJECT_DOMAIN_NAME, - ... project_name=PROJECT_NAME, - ... auth_url=KEYSTONE_URL) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.projects.list() - ... - >>> user = keystone.users.get(USER_ID) - >>> user.delete() - - Instances of this class have the following managers: - - .. py:attribute:: credentials - - :py:class:`keystoneclient.v3.credentials.CredentialManager` - - .. py:attribute:: domain_configs - - :py:class:`keystoneclient.v3.domain_configs.DomainConfigManager` - - .. py:attribute:: ec2 - - :py:class:`keystoneclient.v3.ec2.EC2Manager` - - .. py:attribute:: endpoint_filter - - :py:class:`keystoneclient.v3.contrib.endpoint_filter.\ - EndpointFilterManager` - - .. py:attribute:: endpoint_groups - - :py:class:`keystoneclient.v3.endpoint_groups.\ - EndpointGroupManager` - - .. py:attribute:: endpoint_policy - - :py:class:`keystoneclient.v3.contrib.endpoint_policy.\ - EndpointPolicyManager` - - .. py:attribute:: endpoints - - :py:class:`keystoneclient.v3.endpoints.EndpointManager` - - .. py:attribute:: domains - - :py:class:`keystoneclient.v3.domains.DomainManager` - - .. py:attribute:: federation - - :py:class:`keystoneclient.v3.contrib.federation.core.FederationManager` - - .. py:attribute:: groups - - :py:class:`keystoneclient.v3.groups.GroupManager` - - .. py:attribute:: oauth1 - - :py:class:`keystoneclient.v3.contrib.oauth1.core.OAuthManager` - - .. py:attribute:: policies - - :py:class:`keystoneclient.v3.policies.PolicyManager` - - .. py:attribute:: regions - - :py:class:`keystoneclient.v3.regions.RegionManager` - - .. py:attribute:: role_assignments - - :py:class:`keystoneclient.v3.role_assignments.RoleAssignmentManager` - - .. py:attribute:: roles - - :py:class:`keystoneclient.v3.roles.RoleManager` - - .. py:attribute:: simple_cert - - :py:class:`keystoneclient.v3.contrib.simple_cert.SimpleCertManager` - - .. py:attribute:: services - - :py:class:`keystoneclient.v3.services.ServiceManager` - - .. py:attribute:: tokens - - :py:class:`keystoneclient.v3.tokens.TokenManager` - - .. py:attribute:: trusts - - :py:class:`keystoneclient.v3.contrib.trusts.TrustManager` - - .. py:attribute:: users - - :py:class:`keystoneclient.v3.users.UserManager` - - """ - - version = 'v3' - - def __init__(self, **kwargs): - """Initialize a new client for the Keystone v3 API.""" - super(Client, self).__init__(**kwargs) - - if not kwargs.get('session'): - warnings.warn( - 'Constructing an instance of the ' - 'keystoneclient.v3.client.Client class without a session is ' - 'deprecated as of the 1.7.0 release and may be removed in ' - 'the 2.0.0 release.', DeprecationWarning) - - self.auth = auth.AuthManager(self._adapter) - self.credentials = credentials.CredentialManager(self._adapter) - self.ec2 = ec2.EC2Manager(self._adapter) - self.endpoint_filter = endpoint_filter.EndpointFilterManager( - self._adapter) - self.endpoint_groups = endpoint_groups.EndpointGroupManager( - self._adapter) - self.endpoint_policy = endpoint_policy.EndpointPolicyManager( - self._adapter) - self.endpoints = endpoints.EndpointManager(self._adapter) - self.domain_configs = domain_configs.DomainConfigManager(self._adapter) - self.domains = domains.DomainManager(self._adapter) - self.federation = federation.FederationManager(self._adapter) - self.groups = groups.GroupManager(self._adapter) - self.oauth1 = oauth1.create_oauth_manager(self._adapter) - self.policies = policies.PolicyManager(self._adapter) - self.projects = projects.ProjectManager(self._adapter) - self.regions = regions.RegionManager(self._adapter) - self.role_assignments = ( - role_assignments.RoleAssignmentManager(self._adapter)) - self.roles = roles.RoleManager(self._adapter) - self.inference_rules = roles.InferenceRuleManager(self._adapter) - self.services = services.ServiceManager(self._adapter) - self.simple_cert = simple_cert.SimpleCertManager(self._adapter) - self.tokens = tokens.TokenManager(self._adapter) - self.trusts = trusts.TrustManager(self._adapter) - self.users = users.UserManager(self._adapter) - - # DEPRECATED: if session is passed then we go to the new behaviour of - # authenticating on the first required call. - if 'session' not in kwargs and self.management_url is None: - self.authenticate() - - def serialize(self, entity): - return jsonutils.dumps(entity, sort_keys=True) - - def process_token(self, **kwargs): - """Extract and process information from the new auth_ref. - - And set the relevant authentication information. - """ - super(Client, self).process_token(**kwargs) - if self.auth_ref.domain_scoped: - if not self.auth_ref.domain_id: - raise exceptions.AuthorizationFailure( - _("Token didn't provide domain_id")) - self._process_management_url(kwargs.get('region_name')) - self.domain_name = self.auth_ref.domain_name - self.domain_id = self.auth_ref.domain_id - if self._management_url: - self._management_url = self._management_url.replace('/v2.0', '/v3') - - def get_raw_token_from_identity_service(self, auth_url, user_id=None, - username=None, - user_domain_id=None, - user_domain_name=None, - password=None, - domain_id=None, domain_name=None, - project_id=None, project_name=None, - project_domain_id=None, - project_domain_name=None, - token=None, - trust_id=None, - **kwargs): - """Authenticate against the v3 Identity API. - - If password and token methods are both provided then both methods will - be used in the request. - - :returns: access.AccessInfo if authentication was successful. - :rtype: :class:`keystoneclient.access.AccessInfoV3` - :raises keystoneclient.exceptions.AuthorizationFailure: if unable to - authenticate or validate the existing authorization token. - :raises keystoneclient.exceptions.Unauthorized: if authentication fails - due to invalid token. - - """ - try: - if auth_url is None: - raise ValueError(_("Cannot authenticate without an auth_url")) - - auth_methods = [] - - if token: - auth_methods.append(v3_auth.TokenMethod(token=token)) - - if password: - m = v3_auth.PasswordMethod(user_id=user_id, - username=username, - user_domain_id=user_domain_id, - user_domain_name=user_domain_name, - password=password) - auth_methods.append(m) - - if not auth_methods: - msg = _('A user and password or token is required.') - raise exceptions.AuthorizationFailure(msg) - - plugin = v3_auth.Auth(auth_url, auth_methods, - trust_id=trust_id, - domain_id=domain_id, - domain_name=domain_name, - project_id=project_id, - project_name=project_name, - project_domain_id=project_domain_id, - project_domain_name=project_domain_name) - - return plugin.get_auth_ref(self.session) - except (exceptions.AuthorizationFailure, exceptions.Unauthorized): - _logger.debug('Authorization failed.') - raise - except exceptions.EndpointNotFound: - msg = _('There was no suitable authentication url for this' - ' request') - raise exceptions.AuthorizationFailure(msg) - except Exception as e: - raise exceptions.AuthorizationFailure( - _('Authorization failed: %s') % e) diff --git a/keystoneclient/v3/contrib/__init__.py b/keystoneclient/v3/contrib/__init__.py deleted file mode 100644 index 576bd621..00000000 --- a/keystoneclient/v3/contrib/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -__all__ = tuple() diff --git a/keystoneclient/v3/contrib/endpoint_filter.py b/keystoneclient/v3/contrib/endpoint_filter.py deleted file mode 100644 index 26d5a874..00000000 --- a/keystoneclient/v3/contrib/endpoint_filter.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright 2014 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. - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient.v3 import endpoint_groups -from keystoneclient.v3 import endpoints -from keystoneclient.v3 import projects - - -class EndpointFilterManager(base.Manager): - """Manager class for manipulating project-endpoint associations. - - Project-endpoint associations can be with endpoints directly or via - endpoint groups. - - """ - - OS_EP_FILTER_EXT = '/OS-EP-FILTER' - - def _build_base_url(self, project=None, endpoint=None): - project_id = base.getid(project) - endpoint_id = base.getid(endpoint) - - if project_id and endpoint_id: - api_path = '/projects/%s/endpoints/%s' % (project_id, endpoint_id) - elif project_id: - api_path = '/projects/%s/endpoints' % (project_id) - elif endpoint_id: - api_path = '/endpoints/%s/projects' % (endpoint_id) - else: - msg = _('Must specify a project, an endpoint, or both') - raise exceptions.ValidationError(msg) - - return self.OS_EP_FILTER_EXT + api_path - - def _build_group_base_url(self, project=None, endpoint_group=None): - project_id = base.getid(project) - endpoint_group_id = base.getid(endpoint_group) - - if project_id and endpoint_group_id: - api_path = '/endpoint_groups/%s/projects/%s' % ( - endpoint_group_id, project_id) - elif project_id: - api_path = '/projects/%s/endpoint_groups' % (project_id) - elif endpoint_group_id: - api_path = '/endpoint_groups/%s/projects' % (endpoint_group_id) - else: - msg = _('Must specify a project, an endpoint group, or both') - raise exceptions.ValidationError(msg) - - return self.OS_EP_FILTER_EXT + api_path - - def add_endpoint_to_project(self, project, endpoint): - """Create a project-endpoint association.""" - if not (project and endpoint): - raise ValueError(_('project and endpoint are required')) - - base_url = self._build_base_url(project=project, - endpoint=endpoint) - return super(EndpointFilterManager, self)._put(url=base_url) - - def delete_endpoint_from_project(self, project, endpoint): - """Remove a project-endpoint association.""" - if not (project and endpoint): - raise ValueError(_('project and endpoint are required')) - - base_url = self._build_base_url(project=project, - endpoint=endpoint) - return super(EndpointFilterManager, self)._delete(url=base_url) - - def check_endpoint_in_project(self, project, endpoint): - """Check if project-endpoint association exists.""" - if not (project and endpoint): - raise ValueError(_('project and endpoint are required')) - - base_url = self._build_base_url(project=project, - endpoint=endpoint) - return super(EndpointFilterManager, self)._head(url=base_url) - - def list_endpoints_for_project(self, project): - """List all endpoints for a given project.""" - if not project: - raise ValueError(_('project is required')) - - base_url = self._build_base_url(project=project) - return super(EndpointFilterManager, self)._list( - base_url, - endpoints.EndpointManager.collection_key, - obj_class=endpoints.EndpointManager.resource_class) - - def list_projects_for_endpoint(self, endpoint): - """List all projects for a given endpoint.""" - if not endpoint: - raise ValueError(_('endpoint is required')) - - base_url = self._build_base_url(endpoint=endpoint) - return super(EndpointFilterManager, self)._list( - base_url, - projects.ProjectManager.collection_key, - obj_class=projects.ProjectManager.resource_class) - - def add_endpoint_group_to_project(self, endpoint_group, project): - """Create a project-endpoint group association.""" - if not (project and endpoint_group): - raise ValueError(_('project and endpoint_group are required')) - - base_url = self._build_group_base_url(project=project, - endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._put(url=base_url) - - def delete_endpoint_group_from_project(self, endpoint_group, project): - """Remove a project-endpoint group association.""" - if not (project and endpoint_group): - raise ValueError(_('project and endpoint_group are required')) - - base_url = self._build_group_base_url(project=project, - endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._delete(url=base_url) - - def check_endpoint_group_in_project(self, endpoint_group, project): - """Check if project-endpoint group association exists.""" - if not (project and endpoint_group): - raise ValueError(_('project and endpoint_group are required')) - - base_url = self._build_group_base_url(project=project, - endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._head(url=base_url) - - def list_endpoint_groups_for_project(self, project): - """List all endpoint groups for a given project.""" - if not project: - raise ValueError(_('project is required')) - - base_url = self._build_group_base_url(project=project) - - return super(EndpointFilterManager, self)._list( - base_url, - 'endpoint_groups', - obj_class=endpoint_groups.EndpointGroupManager.resource_class) - - def list_projects_for_endpoint_group(self, endpoint_group): - """List all projects associated with a given endpoint group.""" - if not endpoint_group: - raise ValueError(_('endpoint_group is required')) - - base_url = self._build_group_base_url(endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._list( - base_url, - projects.ProjectManager.collection_key, - obj_class=projects.ProjectManager.resource_class) diff --git a/keystoneclient/v3/contrib/endpoint_policy.py b/keystoneclient/v3/contrib/endpoint_policy.py deleted file mode 100644 index 24148c1a..00000000 --- a/keystoneclient/v3/contrib/endpoint_policy.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 import base -from keystoneclient.i18n import _ -from keystoneclient.v3 import endpoints -from keystoneclient.v3 import policies - - -class EndpointPolicyManager(base.Manager): - """Manager class for manipulating endpoint-policy associations.""" - - OS_EP_POLICY_EXT = 'OS-ENDPOINT-POLICY' - - def _act_on_policy_association_for_endpoint( - self, policy, endpoint, action): - if not (policy and endpoint): - raise ValueError(_('policy and endpoint are required')) - - policy_id = base.getid(policy) - endpoint_id = base.getid(endpoint) - url = ('/policies/%(policy_id)s/%(ext_name)s' - '/endpoints/%(endpoint_id)s') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT, - 'endpoint_id': endpoint_id} - return action(url=url) - - def create_policy_association_for_endpoint(self, policy, endpoint): - """Create an association between a policy and an endpoint.""" - self._act_on_policy_association_for_endpoint( - policy, endpoint, self._put) - - def check_policy_association_for_endpoint(self, policy, endpoint): - """Check an association between a policy and an endpoint.""" - self._act_on_policy_association_for_endpoint( - policy, endpoint, self._head) - - def delete_policy_association_for_endpoint(self, policy, endpoint): - """Delete an association between a policy and an endpoint.""" - self._act_on_policy_association_for_endpoint( - policy, endpoint, self._delete) - - def _act_on_policy_association_for_service(self, policy, service, action): - if not (policy and service): - raise ValueError(_('policy and service are required')) - - policy_id = base.getid(policy) - service_id = base.getid(service) - url = ('/policies/%(policy_id)s/%(ext_name)s' - '/services/%(service_id)s') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT, - 'service_id': service_id} - return action(url=url) - - def create_policy_association_for_service(self, policy, service): - """Create an association between a policy and a service.""" - self._act_on_policy_association_for_service( - policy, service, self._put) - - def check_policy_association_for_service(self, policy, service): - """Check an association between a policy and a service.""" - self._act_on_policy_association_for_service( - policy, service, self._head) - - def delete_policy_association_for_service(self, policy, service): - """Delete an association between a policy and a service.""" - self._act_on_policy_association_for_service( - policy, service, self._delete) - - def _act_on_policy_association_for_region_and_service( - self, policy, region, service, action): - if not (policy and region and service): - raise ValueError(_('policy, region and service are required')) - - policy_id = base.getid(policy) - region_id = base.getid(region) - service_id = base.getid(service) - url = ('/policies/%(policy_id)s/%(ext_name)s' - '/services/%(service_id)s/regions/%(region_id)s') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT, - 'service_id': service_id, - 'region_id': region_id} - return action(url=url) - - def create_policy_association_for_region_and_service( - self, policy, region, service): - """Create an association between a policy and a service in a region.""" - self._act_on_policy_association_for_region_and_service( - policy, region, service, self._put) - - def check_policy_association_for_region_and_service( - self, policy, region, service): - """Check an association between a policy and a service in a region.""" - self._act_on_policy_association_for_region_and_service( - policy, region, service, self._head) - - def delete_policy_association_for_region_and_service( - self, policy, region, service): - """Delete an association between a policy and a service in a region.""" - self._act_on_policy_association_for_region_and_service( - policy, region, service, self._delete) - - def get_policy_for_endpoint(self, endpoint): - """Get the effective policy for an endpoint. - - :param endpoint: endpoint object or ID - - :returns: policies.Policy object - - """ - if not endpoint: - raise ValueError(_('endpoint is required')) - - endpoint_id = base.getid(endpoint) - url = ('/endpoints/%(endpoint_id)s/%(ext_name)s/policy') % { - 'endpoint_id': endpoint_id, - 'ext_name': self.OS_EP_POLICY_EXT} - - _resp, body = self.client.get(url) - return policies.Policy( - self, body[policies.PolicyManager.key], loaded=True) - - def list_endpoints_for_policy(self, policy): - """List endpoints with the effective association to a policy. - - :param policy: policy object or ID - - :returns: list of endpoints that are associated with the policy - - """ - if not policy: - raise ValueError(_('policy is required')) - - policy_id = base.getid(policy) - url = ('/policies/%(policy_id)s/%(ext_name)s/endpoints') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT} - return self._list( - url, - endpoints.EndpointManager.collection_key, - obj_class=endpoints.EndpointManager.resource_class) diff --git a/keystoneclient/v3/contrib/federation/__init__.py b/keystoneclient/v3/contrib/federation/__init__.py deleted file mode 100644 index ee9bcef9..00000000 --- a/keystoneclient/v3/contrib/federation/__init__.py +++ /dev/null @@ -1,13 +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.v3.contrib.federation.core import * # noqa diff --git a/keystoneclient/v3/contrib/federation/base.py b/keystoneclient/v3/contrib/federation/base.py deleted file mode 100644 index 98567a23..00000000 --- a/keystoneclient/v3/contrib/federation/base.py +++ /dev/null @@ -1,40 +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. - -import abc - -from keystoneauth1 import exceptions -from keystoneauth1 import plugin -import six - -from keystoneclient import base - - -@six.add_metaclass(abc.ABCMeta) -class EntityManager(base.Manager): - """Manager class for listing federated accessible objects.""" - - resource_class = None - - @abc.abstractproperty - def object_type(self): - raise exceptions.MethodNotImplemented - - def list(self): - url = '/auth/%s' % self.object_type - try: - tenant_list = self._list(url, self.object_type) - except exceptions.CatalogException: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - tenant_list = self._list(url, self.object_type, - endpoint_filter=endpoint_filter) - return tenant_list diff --git a/keystoneclient/v3/contrib/federation/core.py b/keystoneclient/v3/contrib/federation/core.py deleted file mode 100644 index 2e12cf60..00000000 --- a/keystoneclient/v3/contrib/federation/core.py +++ /dev/null @@ -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.v3.contrib.federation import domains -from keystoneclient.v3.contrib.federation import identity_providers -from keystoneclient.v3.contrib.federation import mappings -from keystoneclient.v3.contrib.federation import projects -from keystoneclient.v3.contrib.federation import protocols -from keystoneclient.v3.contrib.federation import saml -from keystoneclient.v3.contrib.federation import service_providers - - -class FederationManager(object): - def __init__(self, api): - self.identity_providers = identity_providers.IdentityProviderManager( - api) - self.mappings = mappings.MappingManager(api) - self.protocols = protocols.ProtocolManager(api) - self.projects = projects.ProjectManager(api) - self.domains = domains.DomainManager(api) - self.saml = saml.SamlManager(api) - self.service_providers = service_providers.ServiceProviderManager(api) diff --git a/keystoneclient/v3/contrib/federation/domains.py b/keystoneclient/v3/contrib/federation/domains.py deleted file mode 100644 index 4d5e1353..00000000 --- a/keystoneclient/v3/contrib/federation/domains.py +++ /dev/null @@ -1,19 +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.v3.contrib.federation import base as federation_base -from keystoneclient.v3 import domains - - -class DomainManager(federation_base.EntityManager): - object_type = 'domains' - resource_class = domains.Domain diff --git a/keystoneclient/v3/contrib/federation/identity_providers.py b/keystoneclient/v3/contrib/federation/identity_providers.py deleted file mode 100644 index 4675ca36..00000000 --- a/keystoneclient/v3/contrib/federation/identity_providers.py +++ /dev/null @@ -1,113 +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 positional import positional - -from keystoneclient import base - - -class IdentityProvider(base.Resource): - """Object representing Identity Provider container. - - Attributes: - * id: user-defined unique string identifying Identity Provider. - - """ - - pass - - -class IdentityProviderManager(base.CrudManager): - """Manager class for manipulating Identity Providers.""" - - resource_class = IdentityProvider - collection_key = 'identity_providers' - key = 'identity_provider' - base_url = 'OS-FEDERATION' - - def _build_url_and_put(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: kwargs} - return self._update(url, body=body, response_key=self.key, - method='PUT') - - @positional.method(0) - def create(self, id, **kwargs): - """Create Identity Provider object. - - Utilize Keystone URI: - PUT /OS-FEDERATION/identity_providers/$identity_provider - - :param id: unique id of the identity provider. - :param kwargs: optional attributes: description (str), enabled - (boolean) and remote_ids (list). - :returns: an IdentityProvider resource object. - :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` - - """ - return self._build_url_and_put(identity_provider_id=id, - **kwargs) - - def get(self, identity_provider): - """Fetch Identity Provider object. - - Utilize Keystone URI: - GET /OS-FEDERATION/identity_providers/$identity_provider - - :param identity_provider: an object with identity_provider_id - stored inside. - :returns: an IdentityProvider resource object. - :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` - - """ - return super(IdentityProviderManager, self).get( - identity_provider_id=base.getid(identity_provider)) - - def list(self, **kwargs): - """List all Identity Providers. - - Utilize Keystone URI: - GET /OS-FEDERATION/identity_providers - - :returns: a list of IdentityProvider resource objects. - :rtype: List - - """ - return super(IdentityProviderManager, self).list(**kwargs) - - def update(self, identity_provider, **kwargs): - """Update Identity Provider object. - - Utilize Keystone URI: - PATCH /OS-FEDERATION/identity_providers/$identity_provider - - :param identity_provider: an object with identity_provider_id - stored inside. - :returns: an IdentityProvider resource object. - :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` - - """ - return super(IdentityProviderManager, self).update( - identity_provider_id=base.getid(identity_provider), **kwargs) - - def delete(self, identity_provider): - """Delete Identity Provider object. - - Utilize Keystone URI: - DELETE /OS-FEDERATION/identity_providers/$identity_provider - - :param identity_provider: the Identity Provider ID itself or an object - with it stored inside. - - """ - return super(IdentityProviderManager, self).delete( - identity_provider_id=base.getid(identity_provider)) diff --git a/keystoneclient/v3/contrib/federation/mappings.py b/keystoneclient/v3/contrib/federation/mappings.py deleted file mode 100644 index 24a9c7f4..00000000 --- a/keystoneclient/v3/contrib/federation/mappings.py +++ /dev/null @@ -1,153 +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 positional import positional - -from keystoneclient import base - - -class Mapping(base.Resource): - """An object representing mapping container. - - Attributes: - * id: user defined unique string identifying mapping. - - """ - - pass - - -class MappingManager(base.CrudManager): - """Manager class for manipulating federation mappings.""" - - resource_class = Mapping - collection_key = 'mappings' - key = 'mapping' - base_url = 'OS-FEDERATION' - - def _build_url_and_put(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: kwargs} - return self._update(url, body=body, - response_key=self.key, - method='PUT') - - @positional.method(0) - def create(self, mapping_id, **kwargs): - """Create federation mapping. - - Utilize Identity API operation: - PUT /OS-FEDERATION/mappings/$mapping_id - - :param mapping_id: user defined string identifier of the federation - mapping. - :param rules: a list of mapping rules. - - Example of the ``rules`` parameter:: - - [ - { - "local": [ - { - "group": { - "id": "0cd5e9" - } - } - ], - "remote": [ - { - "type": "orgPersonType", - "not_any_of": [ - "Contractor", - "Guest" - ] - } - ] - } - ] - - """ - return self._build_url_and_put( - mapping_id=mapping_id, **kwargs) - - def get(self, mapping): - """Fetch federation mapping identified by mapping id. - - Utilize Identity API operation: - GET /OS-FEDERATION/mappings/$mapping_id - - :param mapping: a Mapping type object with mapping id - stored inside. - - """ - return super(MappingManager, self).get( - mapping_id=base.getid(mapping)) - - def list(self, **kwargs): - """List all federation mappings. - - Utilize Identity API operation: - GET /OS-FEDERATION/mappings - - """ - return super(MappingManager, self).list(**kwargs) - - def update(self, mapping, **kwargs): - """Update federation mapping identified by mapping id. - - Utilize Identity API operation: - PATCH /OS-FEDERATION/mappings/$mapping_id - - :param mapping: a Mapping type object with mapping id - stored inside. - :param rules: a list of mapping rules. - - Example of the ``rules`` parameter:: - - - [ - { - "local": [ - { - "group": { - "id": "0cd5e9" - } - } - ], - "remote": [ - { - "type": "orgPersonType", - "not_any_of": [ - "Contractor", - "Guest" - ] - } - ] - } - ] - - """ - return super(MappingManager, self).update( - mapping_id=base.getid(mapping), **kwargs) - - def delete(self, mapping): - """Delete federation mapping identified by mapping id. - - Utilize Identity API operation: - DELETE /OS-FEDERATION/mappings/$mapping_id - - :param mapping: a Mapping type object with mapping id - stored inside. - - """ - return super(MappingManager, self).delete( - mapping_id=base.getid(mapping)) diff --git a/keystoneclient/v3/contrib/federation/projects.py b/keystoneclient/v3/contrib/federation/projects.py deleted file mode 100644 index 8e657b45..00000000 --- a/keystoneclient/v3/contrib/federation/projects.py +++ /dev/null @@ -1,19 +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.v3.contrib.federation import base as federation_base -from keystoneclient.v3 import projects - - -class ProjectManager(federation_base.EntityManager): - object_type = 'projects' - resource_class = projects.Project diff --git a/keystoneclient/v3/contrib/federation/protocols.py b/keystoneclient/v3/contrib/federation/protocols.py deleted file mode 100644 index 34daf0f7..00000000 --- a/keystoneclient/v3/contrib/federation/protocols.py +++ /dev/null @@ -1,146 +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 positional import positional - -from keystoneclient import base - - -class Protocol(base.Resource): - """An object representing federation protocol container. - - Attributes: - * id: user-defined unique per Identity Provider string identifying - federation protocol. - - """ - - pass - - -class ProtocolManager(base.CrudManager): - """Manager class for manipulating federation protocols.""" - - resource_class = Protocol - collection_key = 'protocols' - key = 'protocol' - base_url = 'OS-FEDERATION/identity_providers' - - def build_url(self, dict_args_in_out=None): - """Build URL for federation protocols.""" - if dict_args_in_out is None: - dict_args_in_out = {} - - identity_provider_id = dict_args_in_out.pop('identity_provider_id', - None) - if identity_provider_id: - base_url = '/'.join([self.base_url, identity_provider_id]) - else: - base_url = self.base_url - - dict_args_in_out.setdefault('base_url', base_url) - return super(ProtocolManager, self).build_url(dict_args_in_out) - - def _build_url_and_put(self, request_body=None, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: request_body} - return self._update(url, body=body, - response_key=self.key, - method='PUT') - - @positional.method(3) - def create(self, protocol_id, identity_provider, mapping, **kwargs): - """Create federation protocol object and tie to the Identity Provider. - - Utilize Identity API operation: - PUT /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param protocol_id: a string type parameter identifying a federation - protocol - :param identity_provider: a string type parameter identifying an - Identity Provider - :param mapping: a base.Resource object with federation mapping id - - """ - return self._build_url_and_put( - request_body={'mapping_id': base.getid(mapping)}, - identity_provider_id=base.getid(identity_provider), - protocol_id=protocol_id, **kwargs) - - def get(self, identity_provider, protocol, **kwargs): - """Fetch federation protocol object tied to the Identity Provider. - - Utilize Identity API operation: - GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param identity_provider: a base.Resource type object with Identity - Provider id stored inside - :param protocol: a base.Resource type object with federation protocol - id stored inside - - """ - return super(ProtocolManager, self).get( - identity_provider_id=base.getid(identity_provider), - protocol_id=base.getid(protocol), **kwargs) - - def list(self, identity_provider, **kwargs): - """List all federation protocol objects tied to the Identity Provider. - - Utilize Identity API operation: - GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols - - :param identity_provider: a base.Resource type object with Identity - Provider id stored inside - - """ - return super(ProtocolManager, self).list( - identity_provider_id=base.getid(identity_provider), **kwargs) - - def update(self, identity_provider, protocol, mapping, **kwargs): - """Update Protocol object tied to the Identity Provider. - - Utilize Identity API operation: - PATCH /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param identity_provider: a base.Resource type object with Identity - Provider id stored inside - :param protocol: a base.Resource type object with federation protocol - id stored inside - :param mapping: a base.Resource object with federation mapping id - - - """ - return super(ProtocolManager, self).update( - identity_provider_id=base.getid(identity_provider), - protocol_id=base.getid(protocol), mapping_id=base.getid(mapping), - **kwargs) - - def delete(self, identity_provider, protocol): - """Delete Protocol object tied to the Identity Provider. - - Utilize Identity API operation: - DELETE /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param identity_provider: a base.Resource type object with - Identity Provider id stored inside - :param protocol: a base.Resource type object with federation - protocol id stored inside - - """ - return super(ProtocolManager, self).delete( - identity_provider_id=base.getid(identity_provider), - protocol_id=base.getid(protocol)) diff --git a/keystoneclient/v3/contrib/federation/saml.py b/keystoneclient/v3/contrib/federation/saml.py deleted file mode 100644 index 9be657a5..00000000 --- a/keystoneclient/v3/contrib/federation/saml.py +++ /dev/null @@ -1,79 +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 import base - - -SAML2_ENDPOINT = '/auth/OS-FEDERATION/saml2' -ECP_ENDPOINT = '/auth/OS-FEDERATION/saml2/ecp' - - -class SamlManager(base.Manager): - """Manager class for creating SAML assertions.""" - - def create_saml_assertion(self, service_provider, token_id): - """Create a SAML assertion from a token. - - Equivalent Identity API call: - POST /auth/OS-FEDERATION/saml2 - - :param service_provider: Service Provider resource. - :type service_provider: string - :param token_id: Token to transform to SAML assertion. - :type token_id: string - - :returns: SAML representation of token_id - :rtype: string - """ - headers, body = self._create_common_request(service_provider, token_id) - resp, body = self.client.post(SAML2_ENDPOINT, json=body, - headers=headers) - return resp.text - - def create_ecp_assertion(self, service_provider, token_id): - """Create an ECP wrapped SAML assertion from a token. - - Equivalent Identity API call: - POST /auth/OS-FEDERATION/saml2/ecp - - :param service_provider: Service Provider resource. - :type service_provider: string - :param token_id: Token to transform to SAML assertion. - :type token_id: string - - :returns: SAML representation of token_id, wrapped in ECP envelope - :rtype: string - """ - headers, body = self._create_common_request(service_provider, token_id) - resp, body = self.client.post(ECP_ENDPOINT, json=body, - headers=headers) - return resp.text - - def _create_common_request(self, service_provider, token_id): - headers = {'Content-Type': 'application/json'} - body = { - 'auth': { - 'identity': { - 'methods': ['token'], - 'token': { - 'id': token_id - } - }, - 'scope': { - 'service_provider': { - 'id': base.getid(service_provider) - } - } - } - } - - return (headers, body) diff --git a/keystoneclient/v3/contrib/federation/service_providers.py b/keystoneclient/v3/contrib/federation/service_providers.py deleted file mode 100644 index f731c394..00000000 --- a/keystoneclient/v3/contrib/federation/service_providers.py +++ /dev/null @@ -1,106 +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 positional import positional - -from keystoneclient import base - - -class ServiceProvider(base.Resource): - """Object representing Service Provider container. - - Attributes: - * id: user-defined unique string identifying Service Provider. - * sp_url: the shibboleth endpoint of a Service Provider. - * auth_url: the authentication url of Service Provider. - - """ - - pass - - -class ServiceProviderManager(base.CrudManager): - """Manager class for manipulating Service Providers.""" - - resource_class = ServiceProvider - collection_key = 'service_providers' - key = 'service_provider' - base_url = 'OS-FEDERATION' - - def _build_url_and_put(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: kwargs} - return self._update(url, body=body, response_key=self.key, - method='PUT') - - @positional.method(0) - def create(self, id, **kwargs): - """Create Service Provider object. - - Utilize Keystone URI: - ``PUT /OS-FEDERATION/service_providers/{id}`` - - :param id: unique id of the service provider. - - """ - return self._build_url_and_put(service_provider_id=id, - **kwargs) - - def get(self, service_provider): - """Fetch Service Provider object. - - Utilize Keystone URI: - ``GET /OS-FEDERATION/service_providers/{id}`` - - :param service_provider: an object with service_provider_id - stored inside. - - """ - return super(ServiceProviderManager, self).get( - service_provider_id=base.getid(service_provider)) - - def list(self, **kwargs): - """List all Service Providers. - - Utilize Keystone URI: - ``GET /OS-FEDERATION/service_providers`` - - """ - return super(ServiceProviderManager, self).list(**kwargs) - - def update(self, service_provider, **kwargs): - """Update the existing Service Provider object on the server. - - Only properties provided to the function are being updated. - - Utilize Keystone URI: - ``PATCH /OS-FEDERATION/service_providers/{id}`` - - :param service_provider: an object with service_provider_id - stored inside. - - """ - return super(ServiceProviderManager, self).update( - service_provider_id=base.getid(service_provider), **kwargs) - - def delete(self, service_provider): - """Delete Service Provider object. - - Utilize Keystone URI: - ``DELETE /OS-FEDERATION/service_providers/{id}`` - - :param service_provider: an object with service_provider_id - stored inside. - - """ - return super(ServiceProviderManager, self).delete( - service_provider_id=base.getid(service_provider)) diff --git a/keystoneclient/v3/contrib/oauth1/__init__.py b/keystoneclient/v3/contrib/oauth1/__init__.py deleted file mode 100644 index e1fb8b79..00000000 --- a/keystoneclient/v3/contrib/oauth1/__init__.py +++ /dev/null @@ -1,13 +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.v3.contrib.oauth1.core import * # noqa diff --git a/keystoneclient/v3/contrib/oauth1/access_tokens.py b/keystoneclient/v3/contrib/oauth1/access_tokens.py deleted file mode 100644 index 37f19415..00000000 --- a/keystoneclient/v3/contrib/oauth1/access_tokens.py +++ /dev/null @@ -1,51 +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 __future__ import unicode_literals - -from keystoneauth1 import plugin - -from keystoneclient import base -from keystoneclient.v3.contrib.oauth1 import utils - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class AccessToken(base.Resource): - pass - - -class AccessTokenManager(base.CrudManager): - """Manager class for manipulating identity OAuth access tokens.""" - - resource_class = AccessToken - - def create(self, consumer_key, consumer_secret, request_key, - request_secret, verifier): - endpoint = utils.OAUTH_PATH + '/access_token' - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - resource_owner_key=request_key, - resource_owner_secret=request_secret, - signature_method=oauth1.SIGNATURE_HMAC, - verifier=verifier) - url = self.client.get_endpoint(interface=plugin.AUTH_INTERFACE).rstrip( - '/') - url, headers, body = oauth_client.sign(url + endpoint, - http_method='POST') - resp, body = self.client.post(endpoint, headers=headers) - token = utils.get_oauth_token_from_body(resp.content) - return self.resource_class(self, token) diff --git a/keystoneclient/v3/contrib/oauth1/auth.py b/keystoneclient/v3/contrib/oauth1/auth.py deleted file mode 100644 index bd4a152e..00000000 --- a/keystoneclient/v3/contrib/oauth1/auth.py +++ /dev/null @@ -1,55 +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.auth.identity import v3 - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class OAuthMethod(v3.AuthMethod): - """OAuth based authentication method. - - :param string consumer_key: Consumer key. - :param string consumer_secret: Consumer secret. - :param string access_key: Access token key. - :param string access_secret: Access token secret. - """ - - _method_parameters = ['consumer_key', 'consumer_secret', - 'access_key', 'access_secret'] - - def __init__(self, **kwargs): - super(OAuthMethod, self).__init__(**kwargs) - if oauth1 is None: - raise NotImplementedError('optional package oauthlib' - ' is not installed') - - def get_auth_data(self, session, auth, headers, **kwargs): - # Add the oauth specific content into the headers - oauth_client = oauth1.Client(self.consumer_key, - client_secret=self.consumer_secret, - resource_owner_key=self.access_key, - resource_owner_secret=self.access_secret, - signature_method=oauth1.SIGNATURE_HMAC) - o_url, o_headers, o_body = oauth_client.sign(auth.token_url, - http_method='POST') - - headers.update(o_headers) - return 'oauth1', {} - - -class OAuth(v3.AuthConstructor): - _auth_method_class = OAuthMethod diff --git a/keystoneclient/v3/contrib/oauth1/consumers.py b/keystoneclient/v3/contrib/oauth1/consumers.py deleted file mode 100644 index 5c81ff47..00000000 --- a/keystoneclient/v3/contrib/oauth1/consumers.py +++ /dev/null @@ -1,54 +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 import base -from keystoneclient.v3.contrib.oauth1 import utils - - -class Consumer(base.Resource): - """Represents an OAuth consumer. - - Attributes: - * id: a uuid that identifies the consumer - * description: a short description of the consumer - """ - - pass - - -class ConsumerManager(base.CrudManager): - """Manager class for manipulating identity consumers.""" - - resource_class = Consumer - collection_key = 'consumers' - key = 'consumer' - base_url = utils.OAUTH_PATH - - def create(self, description=None, **kwargs): - return super(ConsumerManager, self).create( - description=description, - **kwargs) - - def get(self, consumer): - return super(ConsumerManager, self).get( - consumer_id=base.getid(consumer)) - - def update(self, consumer, description=None, **kwargs): - return super(ConsumerManager, self).update( - consumer_id=base.getid(consumer), - description=description, - **kwargs) - - def delete(self, consumer): - return super(ConsumerManager, self).delete( - consumer_id=base.getid(consumer)) diff --git a/keystoneclient/v3/contrib/oauth1/core.py b/keystoneclient/v3/contrib/oauth1/core.py deleted file mode 100644 index 4b0278e1..00000000 --- a/keystoneclient/v3/contrib/oauth1/core.py +++ /dev/null @@ -1,66 +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.i18n import _ -from keystoneclient.v3.contrib.oauth1 import access_tokens -from keystoneclient.v3.contrib.oauth1 import consumers -from keystoneclient.v3.contrib.oauth1 import request_tokens - - -def create_oauth_manager(self): - # NOTE(stevemar): Attempt to import the oauthlib package at this point. - try: - import oauthlib # noqa - # NOTE(stevemar): Return an object instead of raising an exception here, - # this will allow users to see an exception only when trying to access the - # oauth portions of client. Otherwise an exception would be raised - # when the client is created. - except ImportError: - return OAuthManagerOptionalImportProxy() - else: - return OAuthManager(self) - - -class OAuthManager(object): - def __init__(self, api): - self.access_tokens = access_tokens.AccessTokenManager(api) - self.consumers = consumers.ConsumerManager(api) - self.request_tokens = request_tokens.RequestTokenManager(api) - - -class OAuthManagerOptionalImportProxy(object): - """Act as a proxy manager in case oauthlib is no installed. - - This class will only be created if oauthlib is not in the system, - trying to access any of the attributes in name (access_tokens, - consumers, request_tokens), will result in a NotImplementedError, - and a message. - - >>> manager.access_tokens.blah - NotImplementedError: To use 'access_tokens' oauthlib must be installed - - Otherwise, if trying to access an attribute other than the ones in name, - the manager will state that the attribute does not exist. - - >>> manager.dne.blah - AttributeError: 'OAuthManagerOptionalImportProxy' object has no - attribute 'dne' - """ - - def __getattribute__(self, name): - """Return error when name is related to oauthlib and not exist.""" - if name in ('access_tokens', 'consumers', 'request_tokens'): - raise NotImplementedError( - _('To use %r oauthlib must be installed') % name) - return super(OAuthManagerOptionalImportProxy, - self).__getattribute__(name) diff --git a/keystoneclient/v3/contrib/oauth1/request_tokens.py b/keystoneclient/v3/contrib/oauth1/request_tokens.py deleted file mode 100644 index 59f06bcb..00000000 --- a/keystoneclient/v3/contrib/oauth1/request_tokens.py +++ /dev/null @@ -1,73 +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 __future__ import unicode_literals - -from keystoneauth1 import plugin -from six.moves.urllib import parse as urlparse - -from keystoneclient import base -from keystoneclient.v3.contrib.oauth1 import utils - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class RequestToken(base.Resource): - def authorize(self, roles): - try: - retval = self.manager.authorize(self.id, roles) - self = retval - except Exception: - retval = None - - return retval - - -class RequestTokenManager(base.CrudManager): - """Manager class for manipulating identity OAuth request tokens.""" - - resource_class = RequestToken - - def authorize(self, request_token, roles): - """Authorize a request token with specific roles. - - Utilize Identity API operation: - PUT /OS-OAUTH1/authorize/$request_token_id - - :param request_token: a request token that will be authorized, and - can be exchanged for an access token. - :param roles: a list of roles, that will be delegated to the user. - """ - request_id = urlparse.quote(base.getid(request_token)) - endpoint = utils.OAUTH_PATH + '/authorize/%s' % (request_id) - body = {'roles': [{'id': base.getid(r_id)} for r_id in roles]} - return self._put(endpoint, body, "token") - - def create(self, consumer_key, consumer_secret, project): - endpoint = utils.OAUTH_PATH + '/request_token' - headers = {'requested-project-id': base.getid(project)} - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - signature_method=oauth1.SIGNATURE_HMAC, - callback_uri="oob") - url = self.client.get_endpoint(interface=plugin.AUTH_INTERFACE).rstrip( - "/") - url, headers, body = oauth_client.sign(url + endpoint, - http_method='POST', - headers=headers) - resp, body = self.client.post(endpoint, headers=headers) - token = utils.get_oauth_token_from_body(resp.content) - return self.resource_class(self, token) diff --git a/keystoneclient/v3/contrib/oauth1/utils.py b/keystoneclient/v3/contrib/oauth1/utils.py deleted file mode 100644 index 3c5c9d48..00000000 --- a/keystoneclient/v3/contrib/oauth1/utils.py +++ /dev/null @@ -1,38 +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. - -import six -from six.moves.urllib import parse as urlparse - - -OAUTH_PATH = '/OS-OAUTH1' - - -def get_oauth_token_from_body(body): - """Parse the URL response body to retrieve the oauth token key and secret. - - The response body will look like: - 'oauth_token=12345&oauth_token_secret=67890' with - 'oauth_expires_at=2013-03-30T05:27:19.463201' possibly there, too. - """ - if six.PY3: - body = body.decode('utf-8') - - credentials = urlparse.parse_qs(body) - key = credentials['oauth_token'][0] - secret = credentials['oauth_token_secret'][0] - token = {'key': key, 'id': key, 'secret': secret} - expires_at = credentials.get('oauth_expires_at') - if expires_at: - token['expires'] = expires_at[0] - return token diff --git a/keystoneclient/v3/contrib/simple_cert.py b/keystoneclient/v3/contrib/simple_cert.py deleted file mode 100644 index 8168e67a..00000000 --- a/keystoneclient/v3/contrib/simple_cert.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2014 IBM Corp. -# 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. - - -class SimpleCertManager(object): - """Manager for the OS-SIMPLE-CERT extension.""" - - def __init__(self, client): - self._client = client - - def get_ca_certificates(self): - """Get CA certificates. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/OS-SIMPLE-CERT/ca', - authenticated=False) - return resp.text - - def get_certificates(self): - """Get signing certificates. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/OS-SIMPLE-CERT/certificates', - authenticated=False) - return resp.text diff --git a/keystoneclient/v3/contrib/trusts.py b/keystoneclient/v3/contrib/trusts.py deleted file mode 100644 index a8ef5790..00000000 --- a/keystoneclient/v3/contrib/trusts.py +++ /dev/null @@ -1,102 +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 import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import utils - - -class Trust(base.Resource): - """Represents a Trust. - - Attributes: - * id: a uuid that identifies the trust - * impersonation: allow explicit impersonation - * project_id: project ID - * trustee_user_id: a uuid that identifies the trustee - * trustor_user_id: a uuid that identifies the trustor - """ - - pass - - -class TrustManager(base.CrudManager): - """Manager class for manipulating Trusts.""" - - resource_class = Trust - collection_key = 'trusts' - key = 'trust' - base_url = '/OS-TRUST' - - def create(self, trustee_user, trustor_user, role_names=None, - role_ids=None, project=None, impersonation=False, - expires_at=None, remaining_uses=None, **kwargs): - """Create a Trust. - - :param string trustee_user: user who is capable of consuming the trust - :param string trustor_user: user who's authorization is being delegated - :param string role_names: subset of trustor's roles to be granted - :param string role_ids: subset of trustor's roles to be granted - :param string project: project which the trustor is delegating - :param boolean impersonation: enable explicit impersonation - :param datetime.datetime expires_at: expiry time - :param integer remaining_uses: how many times this trust can be used - to generate a token. None means - unlimited tokens. - - """ - # Convert role_names list into list-of-dict API format - roles = [] - if role_names: - roles.extend([{'name': n} for n in role_names]) - if role_ids: - roles.extend([{'id': i} for i in role_ids]) - - if not roles: - roles = None - - # Convert datetime.datetime expires_at to iso format string - if expires_at: - expires_str = utils.isotime(at=expires_at, subsecond=True) - else: - expires_str = None - - return super(TrustManager, self).create( - expires_at=expires_str, - impersonation=impersonation, - project_id=base.getid(project), - remaining_uses=remaining_uses, - roles=roles, - trustee_user_id=base.getid(trustee_user), - trustor_user_id=base.getid(trustor_user), - **kwargs) - - def update(self): - raise exceptions.MethodNotImplemented( - _('Update not supported for trusts')) - - def list(self, trustee_user=None, trustor_user=None, **kwargs): - """List Trusts.""" - trustee_user_id = base.getid(trustee_user) - trustor_user_id = base.getid(trustor_user) - return super(TrustManager, self).list(trustee_user_id=trustee_user_id, - trustor_user_id=trustor_user_id, - **kwargs) - - def get(self, trust): - """Get a specific trust.""" - return super(TrustManager, self).get(trust_id=base.getid(trust)) - - def delete(self, trust): - """Delete a trust.""" - return super(TrustManager, self).delete(trust_id=base.getid(trust)) diff --git a/keystoneclient/v3/credentials.py b/keystoneclient/v3/credentials.py deleted file mode 100644 index 80eb38b3..00000000 --- a/keystoneclient/v3/credentials.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base - - -class Credential(base.Resource): - """Represents an Identity credential. - - Attributes: - * id: a uuid that identifies the credential - * user_id: user ID to which credential belongs - * type: the type of credential - * blob: the text that represents the credential - * project_id: project ID which limits the scope of the credential - - """ - - pass - - -class CredentialManager(base.CrudManager): - """Manager class for manipulating Identity credentials.""" - - resource_class = Credential - collection_key = 'credentials' - key = 'credential' - - @positional(1, enforcement=positional.WARN) - def create(self, user, type, blob, project=None, **kwargs): - """Create a credential. - - :param user: the user to which the credential belongs - :type user: str or :class:`keystoneclient.v3.users.User` - :param str type: the type of the credential, valid values are: - ``ec2``, ``cert`` or ``totp`` - :param str blob: the arbitrary blob of the credential data, to be - parsed according to the type - :param project: the project which limits the scope of the credential, - this attribbute is mandatory if the credential type is - ec2 - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server - - :returns: the created credential - :rtype: :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).create( - user_id=base.getid(user), - type=type, - blob=blob, - project_id=base.getid(project), - **kwargs) - - def get(self, credential): - """Retrieve a credential. - - :param credential: the credential to be retrieved from the server - :type credential: str or - :class:`keystoneclient.v3.credentials.Credential` - - :returns: the specified credential - :rtype: :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).get( - credential_id=base.getid(credential)) - - def list(self, **kwargs): - """List credentials. - - :param kwargs: If user_id or type is specified then credentials - will be filtered accordingly. - - :returns: a list of credentials - :rtype: list of :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).list(**kwargs) - - @positional(2, enforcement=positional.WARN) - def update(self, credential, user, type=None, blob=None, project=None, - **kwargs): - """Update a credential. - - :param credential: the credential to be updated on the server - :type credential: str or - :class:`keystoneclient.v3.credentials.Credential` - :param user: the new user to which the credential belongs - :type user: str or :class:`keystoneclient.v3.users.User` - :param str type: the new type of the credential, valid values are: - ``ec2``, ``cert`` or ``totp`` - :param str blob: the new blob of the credential data - and may be removed in the future release. - :param project: the new project which limits the scope of the - credential, this attribute is mandatory if the - credential type is ec2 - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server - - :returns: the updated credential - :rtype: :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).update( - credential_id=base.getid(credential), - user_id=base.getid(user), - type=type, - blob=blob, - project_id=base.getid(project), - **kwargs) - - def delete(self, credential): - """Delete a credential. - - :param credential: the credential to be deleted - :type credential: str or - :class:`keystoneclient.v3.credentials.Credential` - - :returns: response object with 204 status - :rtype: :class:`requests.models.Response` - - """ - return super(CredentialManager, self).delete( - credential_id=base.getid(credential)) diff --git a/keystoneclient/v3/domain_configs.py b/keystoneclient/v3/domain_configs.py deleted file mode 100644 index 4c011bce..00000000 --- a/keystoneclient/v3/domain_configs.py +++ /dev/null @@ -1,130 +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 import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class DomainConfig(base.Resource): - """An object representing a domain config association. - - This resource object does not necessarily contain fixed attributes, as new - attributes are added in the server, they are supported here directly. - The currently supported configs are `identity` and `ldap`. - - """ - - pass - - -class DomainConfigManager(base.Manager): - """Manager class for manipulating domain config associations.""" - - resource_class = DomainConfig - key = 'config' - - def build_url(self, domain): - return '/domains/%s/config' % base.getid(domain) - - def create(self, domain, config): - """Create a config for a domain. - - :param domain: the domain where the config is going to be applied. - :type domain: str or :py:class:`keystoneclient.v3.domains.Domain` - - :param dict config: a dictionary of domain configurations. - - Example of the ``config`` parameter:: - - { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org" - } - } - - :returns: the created domain config returned from server. - :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig` - - """ - base_url = self.build_url(domain) - body = {self.key: config} - return super(DomainConfigManager, self)._put( - base_url, body=body, response_key=self.key) - - def get(self, domain): - """Get a config for a domain. - - :param domain: the domain for which the config is defined. - :type domain: str or :py:class:`keystoneclient.v3.domains.Domain` - - :returns: the domain config returned from server. - :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig` - - """ - base_url = self.build_url(domain) - return super(DomainConfigManager, self)._get(base_url, self.key) - - def update(self, domain, config): - """Update a config for a domain. - - :param domain: the domain where the config is going to be updated. - :type domain: str or :py:class:`keystoneclient.v3.domains.Domain` - - :param dict config: a dictionary of domain configurations. - - Example of the ``config`` parameter:: - - { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org" - } - } - - :returns: the updated domain config returned from server. - :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig` - - """ - base_url = self.build_url(domain) - body = {self.key: config} - return super(DomainConfigManager, self)._patch( - base_url, body=body, response_key=self.key) - - def delete(self, domain): - """Delete a config for a domain. - - :param domain: the domain which the config will be deleted on - the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - base_url = self.build_url(domain) - return super(DomainConfigManager, self)._delete(url=base_url) - - def find(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Find not supported for domain configs')) - - def list(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('List not supported for domain configs')) diff --git a/keystoneclient/v3/domains.py b/keystoneclient/v3/domains.py deleted file mode 100644 index a790558f..00000000 --- a/keystoneclient/v3/domains.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base - - -class Domain(base.Resource): - """Represents an Identity domain. - - Attributes: - * id: a uuid that identifies the domain - * name: the name of the domain - * description: a description of the domain - * enabled: determines whether the domain is enabled - - """ - - pass - - -class DomainManager(base.CrudManager): - """Manager class for manipulating Identity domains.""" - - resource_class = Domain - collection_key = 'domains' - key = 'domain' - - @positional(1, enforcement=positional.WARN) - def create(self, name, description=None, enabled=True, **kwargs): - """Create a domain. - - :param str name: the name of the domain. - :param str description: a description of the domain. - :param bool enabled: whether the domain is enabled. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created domain returned from server. - :rtype: :class:`keystoneclient.v3.domains.Domain` - - """ - return super(DomainManager, self).create( - name=name, - description=description, - enabled=enabled, - **kwargs) - - def get(self, domain): - """Retrieve a domain. - - :param domain: the domain to be retrieved from the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - - :returns: the specified domain returned from server. - :rtype: :class:`keystoneclient.v3.domains.Domain` - - """ - return super(DomainManager, self).get( - domain_id=base.getid(domain)) - - def list(self, **kwargs): - """List domains. - - :param kwargs: allows filter criteria to be passed where - supported by the server. - - :returns: a list of domains. - :rtype: list of :class:`keystoneclient.v3.domains.Domain`. - - """ - # Ref bug #1267530 we have to pass 0 for False to get the expected - # results on all keystone versions - if kwargs.get('enabled') is False: - kwargs['enabled'] = 0 - return super(DomainManager, self).list(**kwargs) - - @positional(enforcement=positional.WARN) - def update(self, domain, name=None, - description=None, enabled=None, **kwargs): - """Update a domain. - - :param domain: the domain to be updated on the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str name: the new name of the domain. - :param str description: the new description of the domain. - :param bool enabled: whether the domain is enabled. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated domain returned from server. - :rtype: :class:`keystoneclient.v3.domains.Domain` - - """ - return super(DomainManager, self).update( - domain_id=base.getid(domain), - name=name, - description=description, - enabled=enabled, - **kwargs) - - def delete(self, domain): - """"Delete a domain. - - :param domain: the domain to be deleted on the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(DomainManager, self).delete( - domain_id=base.getid(domain)) diff --git a/keystoneclient/v3/ec2.py b/keystoneclient/v3/ec2.py deleted file mode 100644 index d32fbcaa..00000000 --- a/keystoneclient/v3/ec2.py +++ /dev/null @@ -1,98 +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 import base - - -class EC2(base.Resource): - """Represents an EC2 resource. - - Attributes: - * id: a string that identifies the EC2 resource. - * user_id: the ID field of a pre-existing user in the backend. - * project_id: the ID field of a pre-existing project in the backend. - * access: a string representing access key of the access/secret pair. - * secret: a string representing the secret of the access/secret pair. - - """ - - def __repr__(self): - """Return string representation of EC2 resource information.""" - return "" % self._info - - -class EC2Manager(base.ManagerWithFind): - - resource_class = EC2 - - def create(self, user_id, project_id): - """Create a new access/secret pair. - - :param user_id: the ID of the user having access/secret pair. - :type user_id: str or :class:`keystoneclient.v3.users.User` - :param project_id: the ID of the project having access/secret pair. - :type project_id: str or :class:`keystoneclient.v3.projects.Project` - - :returns: the created access/secret pair returned from server. - :rtype: :class:`keystoneclient.v3.ec2.EC2` - - """ - # NOTE(jamielennox): Yes, this uses tenant_id as a key even though we - # are in the v3 API. - return self._post('/users/%s/credentials/OS-EC2' % user_id, - body={'tenant_id': project_id}, - response_key="credential") - - def get(self, user_id, access): - """Retrieve an access/secret pair for a given access key. - - :param user_id: the ID of the user whose access/secret pair will be - retrieved from the server. - :type user_id: str or :class:`keystoneclient.v3.users.User` - :param str access: the access key whose access/secret pair will be - retrieved from the server. - - :returns: the specified access/secret pair returned from server. - :rtype: :class:`keystoneclient.v3.ec2.EC2` - - """ - url = "/users/%s/credentials/OS-EC2/%s" % (user_id, base.getid(access)) - return self._get(url, response_key="credential") - - def list(self, user_id): - """List access/secret pairs for a given user. - - :param str user_id: the ID of the user having access/secret pairs will - be listed. - - :returns: a list of access/secret pairs. - :rtype: list of :class:`keystoneclient.v3.ec2.EC2` - - """ - return self._list("/users/%s/credentials/OS-EC2" % user_id, - response_key="credentials") - - def delete(self, user_id, access): - """Delete an access/secret pair. - - :param user_id: the ID of the user whose access/secret pair will be - deleted on the server. - :type user_id: str or :class:`keystoneclient.v3.users.User` - :param str access: the access key whose access/secret pair will be - deleted on the server. - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return self._delete("/users/%s/credentials/OS-EC2/%s" % - (user_id, base.getid(access))) diff --git a/keystoneclient/v3/endpoint_groups.py b/keystoneclient/v3/endpoint_groups.py deleted file mode 100644 index f8b47c4d..00000000 --- a/keystoneclient/v3/endpoint_groups.py +++ /dev/null @@ -1,136 +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 import base - - -class EndpointGroup(base.Resource): - """Represents an identity endpoint group. - - Attributes: - * id: a UUID that identifies the endpoint group - * name: the endpoint group name - * description: the endpoint group description - * filters: representation of filters in the format of JSON that define - what endpoint entities are part of the group - - """ - - pass - - -class EndpointGroupManager(base.CrudManager): - """Manager class for Endpoint Groups.""" - - resource_class = EndpointGroup - collection_key = 'endpoint_groups' - key = 'endpoint_group' - base_url = 'OS-EP-FILTER' - - def create(self, name, filters, description=None, **kwargs): - """Create an endpoint group. - - :param str name: the name of the endpoint group. - :param str filters: representation of filters in the format of JSON - that define what endpoint entities are part of the - group. - :param str description: a description of the endpoint group. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created endpoint group returned from server. - :rtype: :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - """ - return super(EndpointGroupManager, self).create( - name=name, - filters=filters, - description=description, - **kwargs) - - def get(self, endpoint_group): - """Retrieve an endpoint group. - - :param endpoint_group: the endpoint group to be retrieved from the - server. - :type endpoint_group: - str or :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - :returns: the specified endpoint group returned from server. - :rtype: :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - """ - return super(EndpointGroupManager, self).get( - endpoint_group_id=base.getid(endpoint_group)) - - def check(self, endpoint_group): - """Check if an endpoint group exists. - - :param endpoint_group: the endpoint group to be checked against the - server. - :type endpoint_group: - str or :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - :returns: none if the specified endpoint group exists. - - """ - return super(EndpointGroupManager, self).head( - endpoint_group_id=base.getid(endpoint_group)) - - def list(self, **kwargs): - """List endpoint groups. - - Any parameter provided will be passed to the server. - - :returns: a list of endpoint groups. - :rtype: list of - :class:`keystoneclient.v3.endpoint_groups.EndpointGroup`. - - """ - return super(EndpointGroupManager, self).list(**kwargs) - - def update(self, endpoint_group, name=None, filters=None, - description=None, **kwargs): - """Update an endpoint group. - - :param str name: the new name of the endpoint group. - :param str filters: the new representation of filters in the format of - JSON that define what endpoint entities are part of - the group. - :param str description: the new description of the endpoint group. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated endpoint group returned from server. - :rtype: :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - """ - return super(EndpointGroupManager, self).update( - endpoint_group_id=base.getid(endpoint_group), - name=name, - filters=filters, - description=description, - **kwargs) - - def delete(self, endpoint_group): - """Delete an endpoint group. - - :param endpoint_group: the endpoint group to be deleted on the server. - :type endpoint_group: - str or :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(EndpointGroupManager, self).delete( - endpoint_group_id=base.getid(endpoint_group)) diff --git a/keystoneclient/v3/endpoints.py b/keystoneclient/v3/endpoints.py deleted file mode 100644 index bc8ccb61..00000000 --- a/keystoneclient/v3/endpoints.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -VALID_INTERFACES = ['public', 'admin', 'internal'] - - -class Endpoint(base.Resource): - """Represents an Identity endpoint. - - Attributes: - * id: a uuid that identifies the endpoint - * interface: 'public', 'admin' or 'internal' network interface - * region: geographic location of the endpoint - * service_id: service to which the endpoint belongs - * url: fully qualified service endpoint - * enabled: determines whether the endpoint appears in the service - catalog - - """ - - pass - - -class EndpointManager(base.CrudManager): - """Manager class for manipulating Identity endpoints.""" - - resource_class = Endpoint - collection_key = 'endpoints' - key = 'endpoint' - - def _validate_interface(self, interface): - if interface is not None and interface not in VALID_INTERFACES: - msg = _('"interface" must be one of: %s') - msg %= ', '.join(VALID_INTERFACES) - raise exceptions.ValidationError(msg) - - @positional(1, enforcement=positional.WARN) - def create(self, service, url, interface=None, region=None, enabled=True, - **kwargs): - """Create an endpoint. - - :param service: the service to which the endpoint belongs. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str url: the URL of the fully qualified service endpoint. - :param str interface: the network interface of the endpoint. Valid - values are: ``public``, ``admin`` or ``internal``. - :param region: the region to which the endpoint belongs. - :type region: str or :class:`keystoneclient.v3.regions.Region` - :param bool enabled: whether the endpoint is enabled or not, - determining if it appears in the service catalog. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created endpoint returned from server. - :rtype: :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - self._validate_interface(interface) - return super(EndpointManager, self).create( - service_id=base.getid(service), - interface=interface, - url=url, - region=region, - enabled=enabled, - **kwargs) - - def get(self, endpoint): - """Retrieve an endpoint. - - :param endpoint: the endpoint to be retrieved from the server. - :type endpoint: str or :class:`keystoneclient.v3.endpoints.Endpoint` - - :returns: the specified endpoint returned from server. - :rtype: :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - return super(EndpointManager, self).get( - endpoint_id=base.getid(endpoint)) - - @positional(enforcement=positional.WARN) - def list(self, service=None, interface=None, region=None, enabled=None, - region_id=None, **kwargs): - """List endpoints. - - :param service: the service of the endpoints to be filtered on. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str interface: the network interface of the endpoints to be - filtered on. Valid values are: ``public``, - ``admin`` or ``internal``. - :param bool enabled: whether to return enabled or disabled endpoints. - :param str region_id: filter endpoints by the region_id attribute. If - both region and region_id are specified, region - takes precedence. - :param kwargs: any other attribute provided will filter endpoints on. - - :returns: a list of endpoints. - :rtype: list of :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - # NOTE(lhcheng): region filter is not supported by keystone, - # region_id should be used instead. Consider removing the - # region argument in the next release. - self._validate_interface(interface) - return super(EndpointManager, self).list( - service_id=base.getid(service), - interface=interface, - region_id=region_id or base.getid(region), - enabled=enabled, - **kwargs) - - @positional(enforcement=positional.WARN) - def update(self, endpoint, service=None, url=None, interface=None, - region=None, enabled=None, **kwargs): - """Update an endpoint. - - :param endpoint: the endpoint to be updated on the server. - :type endpoint: str or :class:`keystoneclient.v3.endpoints.Endpoint` - :param service: the new service to which the endpoint belongs. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str url: the new URL of the fully qualified service endpoint. - :param str interface: the new network interface of the endpoint. Valid - values are: ``public``, ``admin`` or ``internal``. - :param region: the new region to which the endpoint belongs. - :type region: str or :class:`keystoneclient.v3.regions.Region` - :param bool enabled: determining if the endpoint appears in the service - catalog by enabling or disabling it. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated endpoint returned from server. - :rtype: :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - self._validate_interface(interface) - return super(EndpointManager, self).update( - endpoint_id=base.getid(endpoint), - service_id=base.getid(service), - interface=interface, - url=url, - region=region, - enabled=enabled, - **kwargs) - - def delete(self, endpoint): - """Delete an endpoint. - - :param endpoint: the endpoint to be deleted on the server. - :type endpoint: str or :class:`keystoneclient.v3.endpoints.Endpoint` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(EndpointManager, self).delete( - endpoint_id=base.getid(endpoint)) diff --git a/keystoneclient/v3/groups.py b/keystoneclient/v3/groups.py deleted file mode 100644 index 2eec3244..00000000 --- a/keystoneclient/v3/groups.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base - - -class Group(base.Resource): - """Represents an Identity user group. - - Attributes: - * id: a uuid that identifies the group - * name: group name - * description: group description - - """ - - @positional(enforcement=positional.WARN) - def update(self, name=None, description=None): - kwargs = { - 'name': name if name is not None else self.name, - 'description': (description - if description is not None - else self.description), - } - - try: - retval = self.manager.update(self.id, **kwargs) - self = retval - except Exception: - retval = None - - return retval - - -class GroupManager(base.CrudManager): - """Manager class for manipulating Identity groups.""" - - resource_class = Group - collection_key = 'groups' - key = 'group' - - @positional(1, enforcement=positional.WARN) - def create(self, name, domain=None, description=None, **kwargs): - """Create a group. - - :param str name: the name of the group. - :param domain: the domain of the group. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str description: a description of the group. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created group returned from server. - :rtype: :class:`keystoneclient.v3.groups.Group` - - """ - return super(GroupManager, self).create( - name=name, - domain_id=base.getid(domain), - description=description, - **kwargs) - - @positional(enforcement=positional.WARN) - def list(self, user=None, domain=None, **kwargs): - """List groups. - - :param user: the user of the groups to be filtered on. - :type user: str or :class:`keystoneclient.v3.users.User` - :param domain: the domain of the groups to be filtered on. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param kwargs: any other attribute provided will filter groups on. - - :returns: a list of groups. - :rtype: list of :class:`keystoneclient.v3.groups.Group`. - - """ - if user: - base_url = '/users/%s' % base.getid(user) - else: - base_url = None - return super(GroupManager, self).list( - base_url=base_url, - domain_id=base.getid(domain), - **kwargs) - - def get(self, group): - """Retrieve a group. - - :param group: the group to be retrieved from the server. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: the specified group returned from server. - :rtype: :class:`keystoneclient.v3.groups.Group` - - """ - return super(GroupManager, self).get( - group_id=base.getid(group)) - - @positional(enforcement=positional.WARN) - def update(self, group, name=None, description=None, **kwargs): - """Update a group. - - :param group: the group to be updated on the server. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param str name: the new name of the group. - :param str description: the new description of the group. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated group returned from server. - :rtype: :class:`keystoneclient.v3.groups.Group` - - """ - return super(GroupManager, self).update( - group_id=base.getid(group), - name=name, - description=description, - **kwargs) - - def delete(self, group): - """Delete a group. - - :param group: the group to be deleted on the server. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(GroupManager, self).delete( - group_id=base.getid(group)) diff --git a/keystoneclient/v3/policies.py b/keystoneclient/v3/policies.py deleted file mode 100644 index a9be680d..00000000 --- a/keystoneclient/v3/policies.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base - - -class Policy(base.Resource): - """Represents an Identity policy. - - Attributes: - * id: a uuid that identifies the policy - * blob: a policy document (blob) - * type: the MIME type of the policy blob - - """ - - @positional(enforcement=positional.WARN) - def update(self, blob=None, type=None): - kwargs = { - 'blob': blob if blob is not None else self.blob, - 'type': type if type is not None else self.type, - } - - try: - retval = self.manager.update(self.id, **kwargs) - self = retval - except Exception: - retval = None - - return retval - - -class PolicyManager(base.CrudManager): - """Manager class for manipulating Identity policies.""" - - resource_class = Policy - collection_key = 'policies' - key = 'policy' - - @positional(1, enforcement=positional.WARN) - def create(self, blob, type='application/json', **kwargs): - """Create a policy. - - :param str blob: the policy document. - :param str type: the MIME type of the policy blob. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created policy returned from server. - :rtype: :class:`keystoneclient.v3.policies.Policy` - - """ - return super(PolicyManager, self).create( - blob=blob, - type=type, - **kwargs) - - def get(self, policy): - """Retrieve a policy. - - :param policy: the policy to be retrieved from the server. - :type policy: str or :class:`keystoneclient.v3.policies.Policy` - - :returns: the specified policy returned from server. - :rtype: :class:`keystoneclient.v3.policies.Policy` - - """ - return super(PolicyManager, self).get( - policy_id=base.getid(policy)) - - def list(self, **kwargs): - """List policies. - - :param kwargs: allows filter criteria to be passed where - supported by the server. - - :returns: a list of policies. - :rtype: list of :class:`keystoneclient.v3.policies.Policy`. - - """ - return super(PolicyManager, self).list(**kwargs) - - @positional(enforcement=positional.WARN) - def update(self, policy, blob=None, type=None, **kwargs): - """Update a policy. - - :param policy: the policy to be updated on the server. - :type policy: str or :class:`keystoneclient.v3.policies.Policy` - :param str blob: the new policy document. - :param str type: the new MIME type of the policy blob. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated policy returned from server. - :rtype: :class:`keystoneclient.v3.policies.Policy` - - """ - return super(PolicyManager, self).update( - policy_id=base.getid(policy), - blob=blob, - type=type, - **kwargs) - - def delete(self, policy): - """"Delete a policy. - - :param policy: the policy to be deleted on the server. - :type policy: str or :class:`keystoneclient.v3.policies.Policy` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(PolicyManager, self).delete( - policy_id=base.getid(policy)) diff --git a/keystoneclient/v3/projects.py b/keystoneclient/v3/projects.py deleted file mode 100644 index 81dcf8d9..00000000 --- a/keystoneclient/v3/projects.py +++ /dev/null @@ -1,222 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class Project(base.Resource): - """Represents an Identity project. - - Attributes: - * id: a uuid that identifies the project - * name: project name - * description: project description - * enabled: boolean to indicate if project is enabled - * parent_id: a uuid representing this project's parent in hierarchy - * parents: a list or a structured dict containing the parents of this - project in the hierarchy - * subtree: a list or a structured dict containing the subtree of this - project in the hierarchy - - """ - - @positional(enforcement=positional.WARN) - def update(self, name=None, description=None, enabled=None): - kwargs = { - 'name': name if name is not None else self.name, - 'description': (description - if description is not None - else self.description), - 'enabled': enabled if enabled is not None else self.enabled, - } - - try: - retval = self.manager.update(self.id, **kwargs) - self = retval - except Exception: - retval = None - - return retval - - -class ProjectManager(base.CrudManager): - """Manager class for manipulating Identity projects.""" - - resource_class = Project - collection_key = 'projects' - key = 'project' - - @positional(3, enforcement=positional.WARN) - def create(self, name, domain, description=None, - enabled=True, parent=None, **kwargs): - """Create a project. - - :param str name: the name of the project. - :param domain: the domain of the project. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str description: the description of the project. - :param bool enabled: whether the project is enabled. - :param parent: the parent of the project in the hierarchy. - :type parent: str or :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created project returned from server. - :rtype: :class:`keystoneclient.v3.projects.Project` - - """ - # NOTE(rodrigods): the API must be backwards compatible, so if an - # application was passing a 'parent_id' before as kwargs, the call - # should not fail. If both 'parent' and 'parent_id' are provided, - # 'parent' will be preferred. - if parent: - kwargs['parent_id'] = base.getid(parent) - - return super(ProjectManager, self).create( - domain_id=base.getid(domain), - name=name, - description=description, - enabled=enabled, - **kwargs) - - @positional(enforcement=positional.WARN) - def list(self, domain=None, user=None, **kwargs): - """List projects. - - :param domain: the domain of the projects to be filtered on. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param user: filter in projects the specified user has role - assignments on. - :type user: str or :class:`keystoneclient.v3.users.User` - :param kwargs: any other attribute provided will filter projects on. - - :returns: a list of projects. - :rtype: list of :class:`keystoneclient.v3.projects.Project` - - """ - base_url = '/users/%s' % base.getid(user) if user else None - return super(ProjectManager, self).list( - base_url=base_url, - domain_id=base.getid(domain), - fallback_to_auth=True, - **kwargs) - - def _check_not_parents_as_ids_and_parents_as_list(self, parents_as_ids, - parents_as_list): - if parents_as_ids and parents_as_list: - msg = _('Specify either parents_as_ids or parents_as_list ' - 'parameters, not both') - raise exceptions.ValidationError(msg) - - def _check_not_subtree_as_ids_and_subtree_as_list(self, subtree_as_ids, - subtree_as_list): - if subtree_as_ids and subtree_as_list: - msg = _('Specify either subtree_as_ids or subtree_as_list ' - 'parameters, not both') - raise exceptions.ValidationError(msg) - - @positional() - def get(self, project, subtree_as_list=False, parents_as_list=False, - subtree_as_ids=False, parents_as_ids=False): - """Retrieve a project. - - :param project: the project to be retrieved from the server. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool subtree_as_list: retrieve projects below this project in - the hierarchy as a flat list. It only - includes the projects in which the current - user has role assignments on. - :param bool parents_as_list: retrieve projects above this project in - the hierarchy as a flat list. It only - includes the projects in which the current - user has role assignments on. - :param bool subtree_as_ids: retrieve the IDs from the projects below - this project in the hierarchy as a - structured dictionary. - :param bool parents_as_ids: retrieve the IDs from the projects above - this project in the hierarchy as a - structured dictionary. - :returns: the specified project returned from server. - :rtype: :class:`keystoneclient.v3.projects.Project` - - :raises keystoneclient.exceptions.ValidationError: if subtree_as_list - and subtree_as_ids or parents_as_list and parents_as_ids are - included at the same time in the call. - - """ - self._check_not_parents_as_ids_and_parents_as_list( - parents_as_ids, parents_as_list) - self._check_not_subtree_as_ids_and_subtree_as_list( - subtree_as_ids, subtree_as_list) - - # According to the API spec, the query params are key only - query_params = [] - if subtree_as_list: - query_params.append('subtree_as_list') - if subtree_as_ids: - query_params.append('subtree_as_ids') - if parents_as_list: - query_params.append('parents_as_list') - if parents_as_ids: - query_params.append('parents_as_ids') - - query = self.build_key_only_query(query_params) - dict_args = {'project_id': base.getid(project)} - url = self.build_url(dict_args_in_out=dict_args) - return self._get(url + query, self.key) - - @positional(enforcement=positional.WARN) - def update(self, project, name=None, domain=None, description=None, - enabled=None, **kwargs): - """Update a project. - - :param project: the project to be updated on the server. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param str name: the new name of the project. - :param domain: the new domain of the project. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str description: the new description of the project. - :param bool enabled: whether the project is enabled. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated project returned from server. - :rtype: :class:`keystoneclient.v3.projects.Project` - - """ - return super(ProjectManager, self).update( - project_id=base.getid(project), - domain_id=base.getid(domain), - name=name, - description=description, - enabled=enabled, - **kwargs) - - def delete(self, project): - """Delete a project. - - :param project: the project to be deleted on the server. - :type project: str or :class:`keystoneclient.v3.projects.Project` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(ProjectManager, self).delete( - project_id=base.getid(project)) diff --git a/keystoneclient/v3/regions.py b/keystoneclient/v3/regions.py deleted file mode 100644 index 7783b3fc..00000000 --- a/keystoneclient/v3/regions.py +++ /dev/null @@ -1,119 +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 import base - - -class Region(base.Resource): - """Represents a Catalog region. - - Attributes: - * id: a string that identifies the region. - * description: a string that describes the region. - * parent_region_id: a pre-existing region in the backend or its ID - field. Allows for hierarchical region organization. - * enabled: determines whether the endpoint appears in the catalog. - """ - - pass - - -class RegionManager(base.CrudManager): - """Manager class for manipulating Identity regions.""" - - resource_class = Region - collection_key = 'regions' - key = 'region' - - def create(self, id=None, description=None, enabled=True, - parent_region=None, **kwargs): - """Create a region. - - :param str id: the unique identifier of the region. If not specified an - ID will be created by the server. - :param str description: the description of the region. - :param bool enabled: whether the region is enabled or not, determining - if it appears in the catalog. - :param parent_region: the parent of the region in the hierarchy. - :type parent_region: str or :class:`keystoneclient.v3.regions.Region` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created region returned from server. - :rtype: :class:`keystoneclient.v3.regions.Region` - - """ - return super(RegionManager, self).create( - id=id, description=description, enabled=enabled, - parent_region_id=base.getid(parent_region), **kwargs) - - def get(self, region): - """Retrieve a region. - - :param region: the region to be retrieved from the server. - :type region: str or :class:`keystoneclient.v3.regions.Region` - - :returns: the specified region returned from server. - :rtype: :class:`keystoneclient.v3.regions.Region` - - """ - return super(RegionManager, self).get( - region_id=base.getid(region)) - - def list(self, **kwargs): - """List regions. - - :param kwargs: any attributes provided will filter regions on. - - :returns: a list of regions. - :rtype: list of :class:`keystoneclient.v3.regions.Region`. - - """ - return super(RegionManager, self).list( - **kwargs) - - def update(self, region, description=None, enabled=None, - parent_region=None, **kwargs): - """Update a region. - - :param region: the region to be updated on the server. - :type region: str or :class:`keystoneclient.v3.regions.Region` - :param str description: the new description of the region. - :param bool enabled: determining if the region appears in the catalog - by enabling or disabling it. - :param parent_region: the new parent of the region in the hierarchy. - :type parent_region: str or :class:`keystoneclient.v3.regions.Region` - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated region returned from server. - :rtype: :class:`keystoneclient.v3.regions.Region` - - """ - return super(RegionManager, self).update( - region_id=base.getid(region), - description=description, - enabled=enabled, - parent_region_id=base.getid(parent_region), - **kwargs) - - def delete(self, region): - """Delete a region. - - :param region: the region to be deleted on the server. - :type region: str or :class:`keystoneclient.v3.regions.Region` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(RegionManager, self).delete( - region_id=base.getid(region)) diff --git a/keystoneclient/v3/role_assignments.py b/keystoneclient/v3/role_assignments.py deleted file mode 100644 index 5360a948..00000000 --- a/keystoneclient/v3/role_assignments.py +++ /dev/null @@ -1,125 +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 import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class RoleAssignment(base.Resource): - """Represents an Identity role assignment. - - Attributes: - * role: an object which contains a role uuid - * user or group: an object which contains either a user or - group uuid - * scope: an object which has either a project or domain object - containing an uuid - """ - - pass - - -class RoleAssignmentManager(base.CrudManager): - """Manager class for manipulating Identity roles assignments.""" - - resource_class = RoleAssignment - collection_key = 'role_assignments' - key = 'role_assignment' - - def _check_not_user_and_group(self, user, group): - if user and group: - msg = _('Specify either a user or group, not both') - raise exceptions.ValidationError(msg) - - def _check_not_domain_and_project(self, domain, project): - if domain and project: - msg = _('Specify either a domain or project, not both') - raise exceptions.ValidationError(msg) - - def list(self, user=None, group=None, project=None, domain=None, role=None, - effective=False, os_inherit_extension_inherited_to=None, - include_subtree=False, include_names=False): - """List role assignments. - - If no arguments are provided, all role assignments in the - system will be listed. - - If both user and group are provided, a ValidationError will be - raised. If both domain and project are provided, it will also - raise a ValidationError. - - :param user: User to be used as query filter. (optional) - :param group: Group to be used as query filter. (optional) - :param project: Project to be used as query filter. - (optional) - :param domain: Domain to be used as query - filter. (optional) - :param role: Role to be used as query filter. (optional) - :param boolean effective: return effective role - assignments. (optional) - :param string os_inherit_extension_inherited_to: - return inherited role assignments for either 'projects' or - 'domains'. (optional) - :param boolean include_subtree: Include subtree (optional) - :param boolean include_names: Display names instead - of IDs. (optional) - """ - self._check_not_user_and_group(user, group) - self._check_not_domain_and_project(domain, project) - - query_params = {} - if user: - query_params['user.id'] = base.getid(user) - if group: - query_params['group.id'] = base.getid(group) - if project: - query_params['scope.project.id'] = base.getid(project) - if domain: - query_params['scope.domain.id'] = base.getid(domain) - if role: - query_params['role.id'] = base.getid(role) - if effective: - query_params['effective'] = effective - if include_names: - query_params['include_names'] = include_names - if os_inherit_extension_inherited_to: - query_params['scope.OS-INHERIT:inherited_to'] = ( - os_inherit_extension_inherited_to) - if include_subtree: - query_params['include_subtree'] = include_subtree - - return super(RoleAssignmentManager, self).list(**query_params) - - def create(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Create not supported for role assignments')) - - def update(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Update not supported for role assignments')) - - def get(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Get not supported for role assignments')) - - def find(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Find not supported for role assignments')) - - def put(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Put not supported for role assignments')) - - def delete(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Delete not supported for role assignments')) diff --git a/keystoneclient/v3/roles.py b/keystoneclient/v3/roles.py deleted file mode 100644 index d5439ffe..00000000 --- a/keystoneclient/v3/roles.py +++ /dev/null @@ -1,536 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 debtcollector import removals -from positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class Role(base.Resource): - """Represents an Identity role. - - Attributes: - * id: a uuid that identifies the role - * name: user-facing identifier - * domain: optional domain for the role - - """ - - pass - - -class InferenceRule(base.Resource): - """Represents a rule that states one role implies another. - - Attributes: - * prior_role: this role implies the other - * implied_role: this role is implied by the other - - """ - - pass - - -class RoleManager(base.CrudManager): - """Manager class for manipulating Identity roles.""" - - resource_class = Role - collection_key = 'roles' - key = 'role' - deprecation_msg = 'keystoneclient.v3.roles.InferenceRuleManager' - - def _role_grants_base_url(self, user, group, domain, project, - use_inherit_extension): - # When called, we have already checked that only one of user & group - # and one of domain & project have been specified - params = {} - - if project: - params['project_id'] = base.getid(project) - base_url = '/projects/%(project_id)s' - elif domain: - params['domain_id'] = base.getid(domain) - base_url = '/domains/%(domain_id)s' - - if use_inherit_extension: - base_url = '/OS-INHERIT' + base_url - - if user: - params['user_id'] = base.getid(user) - base_url += '/users/%(user_id)s' - elif group: - params['group_id'] = base.getid(group) - base_url += '/groups/%(group_id)s' - - return base_url % params - - def _require_domain_xor_project(self, domain, project): - if domain and project: - msg = _('Specify either a domain or project, not both') - raise exceptions.ValidationError(msg) - elif not (domain or project): - msg = _('Must specify either a domain or project') - raise exceptions.ValidationError(msg) - - def _require_user_xor_group(self, user, group): - if user and group: - msg = _('Specify either a user or group, not both') - raise exceptions.ValidationError(msg) - elif not (user or group): - msg = _('Must specify either a user or group') - raise exceptions.ValidationError(msg) - - @positional(1, enforcement=positional.WARN) - def create(self, name, domain=None, **kwargs): - """Create a role. - - :param str name: the name of the role. - :param domain: the domain of the role. If a value is passed it is a - domain-scoped role, otherwise it's a global role. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - domain_id = None - if domain: - domain_id = base.getid(domain) - - return super(RoleManager, self).create( - name=name, - domain_id=domain_id, - **kwargs) - - def get(self, role): - """Retrieve a role. - - :param role: the role to be retrieved from the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: the specified role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - return super(RoleManager, self).get(role_id=base.getid(role)) - - @positional(enforcement=positional.WARN) - def list(self, user=None, group=None, domain=None, - project=None, os_inherit_extension_inherited=False, **kwargs): - """List roles and role grants. - - :param user: filter in role grants for the specified user on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: filter in role grants for the specified group on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: filter in role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: filter in role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will filter roles on. - - :returns: a list of roles. - :rtype: list of :class:`keystoneclient.v3.roles.Role` - - """ - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - if user or group: - self._require_user_xor_group(user, group) - self._require_domain_xor_project(domain, project) - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).list(base_url=base_url, - **kwargs) - - return super(RoleManager, self).list(**kwargs) - - @positional(enforcement=positional.WARN) - def update(self, role, name=None, **kwargs): - """Update a role. - - :param role: the role to be updated on the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param str name: the new name of the role. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - return super(RoleManager, self).update( - role_id=base.getid(role), - name=name, - **kwargs) - - def delete(self, role): - """Delete a role. - - When a role is deleted all the role inferences that have deleted role - as prior role will be deleted as well. - - :param role: the role to be deleted on the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(RoleManager, self).delete( - role_id=base.getid(role)) - - @positional(enforcement=positional.WARN) - def grant(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): - """Grant a role to a user or group on a domain or project. - - :param role: the role to be granted on the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param user: the specified user to have the role granted on a resource. - Domain or project must be specified. User and group are - mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the specified group to have the role granted on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: the domain in which the role will be granted. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: the project in which the role will be granted. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the granted role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - self._require_domain_xor_project(domain, project) - self._require_user_xor_group(user, group) - - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).put(base_url=base_url, - role_id=base.getid(role), - **kwargs) - - @positional(enforcement=positional.WARN) - def check(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): - """Check if a user or group has a role on a domain or project. - - :param user: check for role grants for the specified user on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: check for role grants for the specified group on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: check for role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: check for role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the specified role returned from server if it exists. - :rtype: :class:`keystoneclient.v3.roles.Role` - - :returns: Response object with 204 status if specified role - doesn't exist. - :rtype: :class:`requests.models.Response` - - """ - self._require_domain_xor_project(domain, project) - self._require_user_xor_group(user, group) - - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).head( - base_url=base_url, - role_id=base.getid(role), - os_inherit_extension_inherited=os_inherit_extension_inherited, - **kwargs) - - @positional(enforcement=positional.WARN) - def revoke(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): - """Revoke a role from a user or group on a domain or project. - - :param user: revoke role grants for the specified user on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: revoke role grants for the specified group on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: revoke role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: revoke role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the revoked role returned from server. - :rtype: list of :class:`keystoneclient.v3.roles.Role` - - """ - self._require_domain_xor_project(domain, project) - self._require_user_xor_group(user, group) - - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).delete( - base_url=base_url, - role_id=base.getid(role), - os_inherit_extension_inherited=os_inherit_extension_inherited, - **kwargs) - - @removals.remove(message='Use %s.create instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def create_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).create(prior_role, - implied_role) - - @removals.remove(message='Use %s.delete instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def delete_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).delete(prior_role, - implied_role) - - @removals.remove(message='Use %s.get instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def get_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).get(prior_role, - implied_role) - - @removals.remove(message='Use %s.check instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def check_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).check(prior_role, - implied_role) - - @removals.remove(message='Use %s.list_inference_roles' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def list_role_inferences(self, **kwargs): - return InferenceRuleManager(self.client).list_inference_roles() - - -class InferenceRuleManager(base.CrudManager): - """Manager class for manipulating Identity inference rules.""" - - resource_class = InferenceRule - collection_key = 'role_inferences' - key = 'role_inference' - - def _implied_role_url_tail(self, prior_role, implied_role): - base_url = ('/%(prior_role_id)s/implies/%(implied_role_id)s' % - {'prior_role_id': base.getid(prior_role), - 'implied_role_id': base.getid(implied_role)}) - return base_url - - def create(self, prior_role, implied_role): - """Create an inference rule. - - An inference rule is comprised of two roles, a prior role and an - implied role. The prior role will imply the implied role. - - Valid HTTP return codes: - - * 201: Resource is created successfully - * 404: A role cannot be found - * 409: The inference rule already exists - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: a newly created role inference returned from server. - :rtype: :class:`keystoneclient.v3.roles.InferenceRule` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - _resp, body = self.client.put("/roles" + url_tail) - return self.resource_class(self, body['role_inference']) - - def delete(self, prior_role, implied_role): - """Delete an inference rule. - - When deleting an inference rule, both roles are required. Note that - neither role is deleted, only the inference relationship is dissolved. - - Valid HTTP return codes: - - * 204: Delete request is accepted - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - return self.client.delete("/roles" + url_tail) - - def get(self, prior_role, implied_role): - """Retrieve an inference rule. - - Valid HTTP return codes: - - * 200: Inference rule is returned - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: the specified role inference returned from server. - :rtype: :class:`keystoneclient.v3.roles.InferenceRule` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - _resp, body = self.client.get("/roles" + url_tail) - return self.resource_class(self, body['role_inference']) - - def list(self, prior_role): - """List all roles that a role may imply. - - Valid HTTP return codes: - - * 200: List of inference rules are returned - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: the specified role inference returned from server. - :rtype: :class:`keystoneclient.v3.roles.InferenceRule` - - """ - url_tail = ('/%s/implies' % base.getid(prior_role)) - _resp, body = self.client.get("/roles" + url_tail) - return self.resource_class(self, body['role_inference']) - - def check(self, prior_role, implied_role): - """Check if an inference rule exists. - - Valid HTTP return codes: - - * 204: The rule inference exists - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: response object with 204 status returned from server. - :rtype: :class:`requests.models.Response` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - return self.client.head("/roles" + url_tail) - - def list_inference_roles(self): - """List all rule inferences. - - Valid HTTP return codes: - - * 200: All inference rules are returned - - :param kwargs: attributes provided will be passed to the server. - - :returns: a list of inference rules. - :rtype: list of :class:`keystoneclient.v3.roles.InferenceRule` - - """ - return super(InferenceRuleManager, self).list() - - def update(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Update not supported for rule inferences')) - - def find(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Find not supported for rule inferences')) - - def put(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Put not supported for rule inferences')) diff --git a/keystoneclient/v3/services.py b/keystoneclient/v3/services.py deleted file mode 100644 index d38e2d40..00000000 --- a/keystoneclient/v3/services.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 positional import positional - -from keystoneclient import base - - -class Service(base.Resource): - """Represents an Identity service. - - Attributes: - * id: a uuid that identifies the service - * name: the user-facing name of the service (e.g. Keystone) - * description: a description of the service - * type: the type of the service (e.g. 'compute', 'identity') - * enabled: determines whether the service appears in the catalog - - """ - - pass - - -class ServiceManager(base.CrudManager): - """Manager class for manipulating Identity services.""" - - resource_class = Service - collection_key = 'services' - key = 'service' - - @positional(1, enforcement=positional.WARN) - def create(self, name, type=None, - enabled=True, description=None, **kwargs): - """Create a service. - - :param str name: the name of the service. - :param str type: the type of the service. - :param bool enabled: whether the service appears in the catalog. - :param str description: the description of the service. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created service returned from server. - :rtype: :class:`keystoneclient.v3.services.Service` - - """ - type_arg = type or kwargs.pop('service_type', None) - return super(ServiceManager, self).create( - name=name, - type=type_arg, - description=description, - enabled=enabled, - **kwargs) - - def get(self, service): - """Retrieve a service. - - :param service: the service to be retrieved from the server. - :type service: str or :class:`keystoneclient.v3.services.Service` - - :returns: the specified service returned from server. - :rtype: :class:`keystoneclient.v3.services.Service` - - """ - return super(ServiceManager, self).get( - service_id=base.getid(service)) - - @positional(enforcement=positional.WARN) - def list(self, name=None, type=None, **kwargs): - """List services. - - :param str name: the name of the services to be filtered on. - :param str type: the type of the services to be filtered on. - :param kwargs: any other attribute provided will filter services on. - - :returns: a list of services. - :rtype: list of :class:`keystoneclient.v3.services.Service` - - """ - type_arg = type or kwargs.pop('service_type', None) - return super(ServiceManager, self).list( - name=name, - type=type_arg, - **kwargs) - - @positional(enforcement=positional.WARN) - def update(self, service, name=None, type=None, enabled=None, - description=None, **kwargs): - """Update a service. - - :param service: the service to be updated on the server. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str name: the new name of the service. - :param str type: the new type of the service. - :param bool enabled: whether the service appears in the catalog. - :param str description: the new description of the service. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated service returned from server. - :rtype: :class:`keystoneclient.v3.services.Service` - - """ - type_arg = type or kwargs.pop('service_type', None) - return super(ServiceManager, self).update( - service_id=base.getid(service), - name=name, - type=type_arg, - description=description, - enabled=enabled, - **kwargs) - - def delete(self, service=None, id=None): - """Delete a service. - - :param service: the service to be deleted on the server. - :type service: str or :class:`keystoneclient.v3.services.Service` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - if service: - service_id = base.getid(service) - else: - service_id = id - return super(ServiceManager, self).delete( - service_id=service_id) diff --git a/keystoneclient/v3/tokens.py b/keystoneclient/v3/tokens.py deleted file mode 100644 index 77f60458..00000000 --- a/keystoneclient/v3/tokens.py +++ /dev/null @@ -1,111 +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 positional import positional - -from keystoneclient import access -from keystoneclient import base - - -def _calc_id(token): - if isinstance(token, access.AccessInfo): - return token.auth_token - - return base.getid(token) - - -class TokenManager(object): - """Manager class for manipulating Identity tokens.""" - - def __init__(self, client): - self._client = client - - def revoke_token(self, token): - """Revoke a token. - - :param token: The token to be revoked. - :type token: str or :class:`keystoneclient.access.AccessInfo` - - """ - token_id = _calc_id(token) - headers = {'X-Subject-Token': token_id} - return self._client.delete('/auth/tokens', headers=headers) - - @positional.method(0) - def get_revoked(self, audit_id_only=False): - """Get revoked tokens list. - - :param bool audit_id_only: If true, the server is requested to not send - token IDs, but only audit IDs instead. - **New in version 2.2.0.** - :returns: A dict containing ``signed`` which is a CMS formatted string - if the server signed the response. If `audit_id_only` is true - then the response may be a dict containing ``revoked`` which - is the list of token audit IDs and expiration times. - :rtype: dict - - """ - path = '/auth/tokens/OS-PKI/revoked' - if audit_id_only: - path += '?audit_id_only' - resp, body = self._client.get(path) - return body - - @positional.method(1) - def get_token_data(self, token, include_catalog=True, allow_expired=False): - """Fetch the data about a token from the identity server. - - :param str token: The ID of the token to be fetched. - :param bool include_catalog: Whether the service catalog should be - included in the response. - :param allow_expired: If True the token will be validated and returned - if it has already expired. - - :rtype: dict - - """ - headers = {'X-Subject-Token': token} - flags = [] - - url = '/auth/tokens' - - if not include_catalog: - flags.append('nocatalog') - if allow_expired: - flags.append('allow_expired=1') - - if flags: - url = '%s?%s' % (url, '&'.join(flags)) - - resp, body = self._client.get(url, headers=headers) - return body - - @positional.method(1) - def validate(self, token, include_catalog=True, allow_expired=False): - """Validate a token. - - :param token: The token to be validated. - :type token: str or :class:`keystoneclient.access.AccessInfo` - :param include_catalog: If False, the response is requested to not - include the catalog. - :param allow_expired: If True the token will be validated and returned - if it has already expired. - :type allow_expired: bool - - :rtype: :class:`keystoneclient.access.AccessInfoV3` - - """ - token_id = _calc_id(token) - body = self.get_token_data(token_id, - include_catalog=include_catalog, - allow_expired=allow_expired) - return access.AccessInfo.factory(auth_token=token_id, body=body) diff --git a/keystoneclient/v3/users.py b/keystoneclient/v3/users.py deleted file mode 100644 index 31cad395..00000000 --- a/keystoneclient/v3/users.py +++ /dev/null @@ -1,300 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# 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 debtcollector import renames -from positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class User(base.Resource): - """Represents an Identity user. - - Attributes: - * id: a uuid that identifies the user - - """ - - pass - - -class UserManager(base.CrudManager): - """Manager class for manipulating Identity users.""" - - resource_class = User - collection_key = 'users' - key = 'user' - - def _require_user_and_group(self, user, group): - if not (user and group): - msg = _('Specify both a user and a group') - raise exceptions.ValidationError(msg) - - @renames.renamed_kwarg('project', 'default_project', version='1.7.0', - removal_version='2.0.0') - @positional(1, enforcement=positional.WARN) - def create(self, name, domain=None, project=None, password=None, - email=None, description=None, enabled=True, - default_project=None, **kwargs): - """Create a user. - - :param str name: the name of the user. - :param domain: the domain of the user. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: the default project of the user. - (deprecated, see warning below) - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param str password: the password for the user. - :param str email: the email address of the user. - :param str description: a description of the user. - :param bool enabled: whether the user is enabled. - :param default_project: the default project of the user. - :type default_project: str or - :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created user returned from server. - :rtype: :class:`keystoneclient.v3.users.User` - - .. warning:: - - The project argument is deprecated as of the 1.7.0 release in favor - of default_project and may be removed in the 2.0.0 release. - - If both default_project and project is provided, the default_project - will be used. - - """ - default_project_id = base.getid(default_project) or base.getid(project) - user_data = base.filter_none(name=name, - domain_id=base.getid(domain), - default_project_id=default_project_id, - password=password, - email=email, - description=description, - enabled=enabled, - **kwargs) - - return self._post('/users', {'user': user_data}, 'user', - log=not bool(password)) - - @renames.renamed_kwarg('project', 'default_project', version='1.7.0', - removal_version='2.0.0') - @positional(enforcement=positional.WARN) - def list(self, project=None, domain=None, group=None, default_project=None, - **kwargs): - """List users. - - :param project: the default project of the users to be filtered on. - (deprecated, see warning below) - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param domain: the domain of the users to be filtered on. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param group: the group in which the users are member of. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param default_project: the default project of the users to be filtered - on. - :type default_project: str or - :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will filter users on. - - :returns: a list of users. - :rtype: list of :class:`keystoneclient.v3.users.User`. - - .. warning:: - - The project argument is deprecated as of the 1.7.0 release in favor - of default_project and may be removed in the 2.0.0 release. - - If both default_project and project is provided, the default_project - will be used. - - """ - default_project_id = base.getid(default_project) or base.getid(project) - if group: - base_url = '/groups/%s' % base.getid(group) - else: - base_url = None - - return super(UserManager, self).list( - base_url=base_url, - domain_id=base.getid(domain), - default_project_id=default_project_id, - **kwargs) - - def get(self, user): - """Retrieve a user. - - :param user: the user to be retrieved from the server. - :type user: str or :class:`keystoneclient.v3.users.User` - - :returns: the specified user returned from server. - :rtype: :class:`keystoneclient.v3.users.User` - - """ - return super(UserManager, self).get( - user_id=base.getid(user)) - - @renames.renamed_kwarg('project', 'default_project', version='1.7.0', - removal_version='2.0.0') - @positional(enforcement=positional.WARN) - def update(self, user, name=None, domain=None, project=None, password=None, - email=None, description=None, enabled=None, - default_project=None, **kwargs): - """Update a user. - - :param user: the user to be updated on the server. - :type user: str or :class:`keystoneclient.v3.users.User` - :param str name: the new name of the user. - :param domain: the new domain of the user. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: the new default project of the user. - (deprecated, see warning below) - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param str password: the new password of the user. - :param str email: the new email of the user. - :param str description: the newdescription of the user. - :param bool enabled: whether the user is enabled. - :param default_project: the new default project of the user. - :type default_project: str or - :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated user returned from server. - :rtype: :class:`keystoneclient.v3.users.User` - - .. warning:: - - The project argument is deprecated as of the 1.7.0 release in favor - of default_project and may be removed in the 2.0.0 release. - - If both default_project and project is provided, the default_project - will be used. - - """ - default_project_id = base.getid(default_project) or base.getid(project) - user_data = base.filter_none(name=name, - domain_id=base.getid(domain), - default_project_id=default_project_id, - password=password, - email=email, - description=description, - enabled=enabled, - **kwargs) - - return self._update('/users/%s' % base.getid(user), - {'user': user_data}, - 'user', - method='PATCH', - log=False) - - def update_password(self, old_password, new_password): - """Update the password for the user the token belongs to. - - :param str old_password: the user's old password - :param str new_password: the user's new password - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - if not (old_password and new_password): - msg = _('Specify both the current password and a new password') - raise exceptions.ValidationError(msg) - - if old_password == new_password: - msg = _('Old password and new password must be different.') - raise exceptions.ValidationError(msg) - - params = {'user': {'password': new_password, - 'original_password': old_password}} - - base_url = '/users/%s/password' % self.client.user_id - - return self._update(base_url, params, method='POST', log=False) - - def add_to_group(self, user, group): - """Add the specified user as a member of the specified group. - - :param user: the user to be added to the group. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the group to put the user in. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - self._require_user_and_group(user, group) - - base_url = '/groups/%s' % base.getid(group) - return super(UserManager, self).put( - base_url=base_url, - user_id=base.getid(user)) - - def check_in_group(self, user, group): - """Check if the specified user is a member of the specified group. - - :param user: the user to be verified in the group. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the group to check the user in. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - self._require_user_and_group(user, group) - - base_url = '/groups/%s' % base.getid(group) - return super(UserManager, self).head( - base_url=base_url, - user_id=base.getid(user)) - - def remove_from_group(self, user, group): - """Remove the specified user from the specified group. - - :param user: the user to be removed from the group. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the group to remove the user from. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - self._require_user_and_group(user, group) - - base_url = '/groups/%s' % base.getid(group) - return super(UserManager, self).delete( - base_url=base_url, - user_id=base.getid(user)) - - def delete(self, user): - """Delete a user. - - :param user: the user to be deleted on the server. - :type user: str or :class:`keystoneclient.v3.users.User` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(UserManager, self).delete( - user_id=base.getid(user)) diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml b/releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml deleted file mode 100644 index 6a3f6cad..00000000 --- a/releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Added a ``allow_expired`` argument to ``validate`` and ``get_token_data`` - in `keystoneclient.v3.tokens`. Setting this to ``True``, allos for a token - validation query to fetch expired tokens. diff --git a/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml b/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml deleted file mode 100644 index e6ae2b08..00000000 --- a/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - Added support for ``domain configs``. A user can now - upload domain specific configurations to keytone - using the client. See ``client.domain_configs.create``, - ``client.domain_configs.delete``, ``client.domain_configs.get`` - and ``client.domain_configs.update``. diff --git a/releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml b/releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml deleted file mode 100644 index 2699a7f5..00000000 --- a/releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Added ability to filter on multiple values with the same parameter key. - For example, we can now filter on user names that contain both ``test`` and - ``user`` using ``keystone.users.list(name__contains=['test', 'user'])``. diff --git a/releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml b/releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml deleted file mode 100644 index e9c1c9c3..00000000 --- a/releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -fixes: - - > - [`bug 1616105 `_] - Only log the response body when the ``Content-Type`` header is set to - ``application/json``. This avoids logging large binary objects (such as - images). Other ``Content-Type`` will not be logged. Additional - ``Content-Type`` strings can be added as required. diff --git a/releasenotes/notes/bug-1641674-4862454115265e76.yaml b/releasenotes/notes/bug-1641674-4862454115265e76.yaml deleted file mode 100644 index 19c8ecc3..00000000 --- a/releasenotes/notes/bug-1641674-4862454115265e76.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -prelude: > - Keystone Client now supports endpoint group filtering. -features: - - | - Support for handling the relationship between endpoint groups and projects - has been added. It is now possible to list, associate, check and - disassociate endpoint groups that have access to a project. diff --git a/releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml b/releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml deleted file mode 100644 index 5d066e90..00000000 --- a/releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - | - The ``X-Service-Token`` header value is now properly masked, and is - displayed as a hash value, in the log. diff --git a/releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml b/releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml deleted file mode 100644 index fd08a910..00000000 --- a/releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -deprecations: - - > - [`blueprint deprecate-to-ksa `_] - Several modules related to authentication in keystoneclient have been - deprecated in favor of [`keystoneauth `_] - These modules include: ``keystoneclient.session``, ``keystoneclient.adapter``, - ``keystoneclient.httpclient``, ``keystoneclient.auth.base``, - ``keystoneclient.auth.cli``, ``keystoneclient.auth.conf``, - ``keystoneclient.auth.identity.base``, and ``keystoneclient.auth.token_endpoint``. - Tips for migrating to `keystoneauth` have been - [`documented `_]. diff --git a/releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml b/releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml deleted file mode 100644 index e00ccae1..00000000 --- a/releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - support for implied roles in v3 API. diff --git a/releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml b/releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml deleted file mode 100644 index e95c939b..00000000 --- a/releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -fixes: - - > - [`bug 1462694 `_] - Add support for `include_subtree` in list_role_assignments. - - > - [`bug 1526686 `_] - Replace textwrap with faster code in cms functions. - - > - [`bug 1457702 `_] - Change default endpoint to public for keystone v3. - - > - [`bug 1520244 `_] - Support `truncated` flag returned from server. -other: - - > - Support v2 parameters for the v3 service create method. diff --git a/releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml b/releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml deleted file mode 100644 index 499306a4..00000000 --- a/releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - > - [`bug 1479569 `_] - With the ``include_names`` parameter set to True the names of the role assignments - are returned with the entities IDs. (GET /role_assignments?include_names=True) diff --git a/releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml b/releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml deleted file mode 100644 index 01ebe3e1..00000000 --- a/releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -prelude: > - The ``data`` argument for creating and updating credentials has - been removed. -other: - - The ``data`` argument for creating and updating credentials was - deprecated in the 1.7.0 release. It has been replaced by the - ``blob`` argument. diff --git a/releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml b/releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml deleted file mode 100644 index cd9859cc..00000000 --- a/releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -prelude: > - keystoneclient.middleware has been removed. -critical: - - > - [`bug 1449066 `_] - The `keystoneclient.middleware` module has been removed in favor of the - keystonemiddleware library. The aforementioned module has been deprecated - since keystoneclient v0.10.0 which was included in the Juno release - of OpenStack. diff --git a/releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml b/releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml deleted file mode 100644 index 24a25d7e..00000000 --- a/releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -other: - - > - Removed `keystoneclient.apiclient.exceptions`. This file was deprecated - in v0.7.1 and has now been replaced by `keystoneclient.exceptions`. diff --git a/releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml b/releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml deleted file mode 100644 index 1fbe6b72..00000000 --- a/releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -prelude: > - keystoneclient.apiclient has been removed. -critical: - - > - [`bug 1526651 `_] - The `keystoneclient.apiclient` module has been removed in favor of - `keystoneclient.exceptions`. The aforementioned module has been deprecated - since keystoneclient v0.7.1 which was inclued in the Juno release - of OpenStack. diff --git a/releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml b/releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml deleted file mode 100644 index c1428096..00000000 --- a/releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -prelude: > - The ``keystone`` CLI has been removed. -other: - - The ``keystone`` CLI has been removed, using the ``openstack`` - CLI is recommended. This feature has been deprecated since the - Liberty release of Keystone. diff --git a/releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml b/releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml deleted file mode 100644 index 61b9d17a..00000000 --- a/releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - Deprecate the `keystoneclient.generic` client. This client used to be able - to determine available API versions and some basics around installed - extensions however the APIs were never upgraded for the v3 API. It doesn't - seem to be used in the openstack ecosystem. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index cc58e398..00000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,285 +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. - -# keystoneclient Release Notes documentation build configuration file, created -# by sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'keystoneclient Release Notes' -copyright = u'2015, Keystone Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -import pbr.version -keystone_version = pbr.version.VersionInfo('keystoneclient') -# The full version, including alpha/beta/rc tags. -release = keystone_version.version_string_with_vcs() -# The short X.Y version. -version = keystone_version.canonical_version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'KeystoneClientReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'keystoneclientReleaseNotes.tex', - u'keystoneclient Release Notes Documentation', - u'Keystone Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'keystoneclientreleasenotes', - u'keystoneclient Release Notes Documentation', - [u'Keystone Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'keystoneclientReleaseNotes', - u'keystoneclient Release Notes Documentation', - u'Keystone Developers', 'keystoneclientReleaseNotes', - 'Python bindings for the OpenStack Identity service.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] - -# -- Options for openstackdocstheme ------------------------------------------- -repository_name = 'openstack/python-keystoneclient' -bug_project = 'python-keystoneclient' -bug_tag = '' diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 10af6372..00000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -============================== - keystoneclient Release Notes -============================== - -.. toctree:: - :maxdepth: 1 - - unreleased - ocata - newton - mitaka diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst deleted file mode 100644 index e5456096..00000000 --- a/releasenotes/source/mitaka.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Mitaka Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/mitaka diff --git a/releasenotes/source/newton.rst b/releasenotes/source/newton.rst deleted file mode 100644 index 7b7d7352..00000000 --- a/releasenotes/source/newton.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= - Newton Series Release Notes -============================= - -.. release-notes:: - :branch: origin/stable/newton diff --git a/releasenotes/source/ocata.rst b/releasenotes/source/ocata.rst deleted file mode 100644 index 9515f6cf..00000000 --- a/releasenotes/source/ocata.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================ - Ocata Series Release Notes -============================ - -.. release-notes:: - :branch: origin/stable/ocata diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index cd22aabc..00000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. release-notes:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 21add6b2..00000000 --- a/requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr!=2.1.0,>=2.0.0 # Apache-2.0 - -debtcollector>=1.2.0 # Apache-2.0 -keystoneauth1>=3.0.1 # Apache-2.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 -positional>=1.1.1 # Apache-2.0 -requests>=2.14.2 # Apache-2.0 -six>=1.9.0 # MIT -stevedore>=1.20.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8995a9cd..00000000 --- a/setup.cfg +++ /dev/null @@ -1,69 +0,0 @@ -[metadata] -name = python-keystoneclient -summary = Client Library for OpenStack Identity -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://docs.openstack.org/python-keystoneclient/latest/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 - -[files] -packages = - keystoneclient - -[entry_points] -keystoneclient.auth.plugin = - password = keystoneclient.auth.identity.generic:Password - token = keystoneclient.auth.identity.generic:Token - admin_token = keystoneclient.auth.token_endpoint:Token - v2password = keystoneclient.auth.identity.v2:Password - v2token = keystoneclient.auth.identity.v2:Token - v3password = keystoneclient.auth.identity.v3:Password - v3token = keystoneclient.auth.identity.v3:Token - v3oidcpassword = keystoneclient.contrib.auth.v3.oidc:OidcPassword - v3unscopedsaml = keystoneclient.contrib.auth.v3.saml2:Saml2UnscopedToken - v3scopedsaml = keystoneclient.contrib.auth.v3.saml2:Saml2ScopedToken - v3unscopedadfs = keystoneclient.contrib.auth.v3.saml2:ADFSUnscopedToken - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 -warning-is-error = 1 - -[pbr] -autodoc_tree_index_modules = True -autodoc_tree_excludes = - setup.py - keystoneclient/tests/ - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = keystoneclient/locale -domain = keystoneclient - -[update_catalog] -domain = keystoneclient -output_dir = keystoneclient/locale -input_file = keystoneclient/locale/keystoneclient.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = keystoneclient/locale/keystoneclient.pot - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d8443..00000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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 FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 10c49e5a..00000000 --- a/test-requirements.txt +++ /dev/null @@ -1,26 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking<0.11,>=0.10.0 -flake8-docstrings==0.2.1.post1 # MIT - -coverage!=4.4,>=4.0 # Apache-2.0 -fixtures>=3.0.0 # Apache-2.0/BSD -keyring>=5.5.1 # MIT/PSF -lxml!=3.7.0,>=2.3 # BSD -mock>=2.0 # BSD -oauthlib>=0.6 # BSD -openstackdocstheme>=1.11.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -reno!=2.3.1,>=1.8.0 # Apache-2.0 -requests-mock>=1.1 # Apache-2.0 -sphinx>=1.6.2 # BSD -tempest>=16.1.0 # Apache-2.0 -testrepository>=0.0.18 # Apache-2.0/BSD -testresources>=0.2.4 # Apache-2.0/BSD -testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT - -# Bandit security code scanner -bandit>=1.1.0 # Apache-2.0 diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index e61b63a8..00000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. - -CONSTRAINTS_FILE="$1" -shift 1 - -set -e - -# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get -# published to logs.openstack.org for easy debugging. -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ "$CONSTRAINTS_FILE" != http* ]]; then - CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE" -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile" - -pip install -c"$localfile" openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints "$localfile" -- "$CLIENT_NAME" - -pip install -c"$localfile" -U "$@" -exit $? diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 08ba9624..00000000 --- a/tox.ini +++ /dev/null @@ -1,74 +0,0 @@ -[tox] -minversion = 2.0 -skipsdist = True -envlist = py35,py27,pep8,releasenotes - -[testenv] -usedevelop = True -install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -setenv = VIRTUAL_ENV={envdir} - BRANCH_NAME=master - CLIENT_NAME=python-keystoneclient - OS_STDOUT_NOCAPTURE=False - OS_STDERR_NOCAPTURE=False - -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = find . -type f -name "*.pyc" -delete - python setup.py testr --slowest --testr-args='{posargs}' -whitelist_externals = find - -[testenv:pep8] -commands = - flake8 - bandit -r keystoneclient -x tests -n5 - -[testenv:bandit] -# NOTE(browne): This is required for the integration test job of the bandit -# project. Please do not remove. -commands = bandit -r keystoneclient -x tests -n5 - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='{posargs}' - coverage report - -[testenv:debug] -commands = oslo_debug_helper -t keystoneclient/tests {posargs} - -[testenv:functional] -setenv = {[testenv]setenv} - OS_TEST_PATH=./keystoneclient/tests/functional -passenv = OS_* - -[flake8] -# D100: Missing docstring in public module -# D101: Missing docstring in public class -# D102: Missing docstring in public method -# D103: Missing docstring in public function -# D104: Missing docstring in public package -# D203: 1 blank line required before class docstring (deprecated in pep257) -ignore = D100,D101,D102,D103,D104,D203 -show-source = True -exclude = .venv,.tox,dist,doc,*egg,build - -[testenv:docs] -commands= - python setup.py build_sphinx - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html - -[hacking] -import_exceptions = - keystoneclient.i18n - -[testenv:bindep] -# Do not install any requirements. We want this to be fast and work even if -# system dependencies are missing, since it's used to tell you what system -# dependencies are missing! This also means that bindep must be installed -# separately, outside of the requirements files. -deps = bindep -commands = bindep test