├── .coveragerc ├── .git-blame-ignore-revs ├── .gitignore ├── .gitreview ├── .mailmap ├── .pre-commit-config.yaml ├── .stestr.conf ├── .zuul.yaml ├── CONTRIBUTING.rst ├── HACKING.rst ├── LICENSE ├── README.rst ├── bindep.txt ├── doc ├── .gitignore ├── Makefile ├── ext │ ├── __init__.py │ └── list_plugins.py ├── requirements.txt └── source │ ├── authentication-plugins.rst │ ├── conf.py │ ├── extras.rst │ ├── images │ ├── graphs_authComp.svg │ └── graphs_authCompDelegate.svg │ ├── index.rst │ ├── migrating.rst │ ├── plugin-options.rst │ └── using-sessions.rst ├── keystoneauth1 ├── __init__.py ├── _fair_semaphore.py ├── _utils.py ├── access │ ├── __init__.py │ ├── access.py │ ├── service_catalog.py │ ├── service_providers.py │ └── types.py ├── adapter.py ├── discover.py ├── exceptions │ ├── __init__.py │ ├── auth.py │ ├── auth_plugins.py │ ├── base.py │ ├── catalog.py │ ├── connection.py │ ├── discovery.py │ ├── http.py │ ├── oidc.py │ ├── response.py │ └── service_providers.py ├── extras │ ├── __init__.py │ ├── _saml2 │ │ ├── __init__.py │ │ ├── _loading.py │ │ └── v3 │ │ │ ├── __init__.py │ │ │ ├── adfs.py │ │ │ ├── base.py │ │ │ └── saml2.py │ ├── kerberos │ │ ├── __init__.py │ │ └── _loading.py │ └── oauth1 │ │ ├── __init__.py │ │ ├── _loading.py │ │ └── v3.py ├── fixture │ ├── __init__.py │ ├── discovery.py │ ├── exception.py │ ├── hooks.py │ ├── keystoneauth_betamax.py │ ├── plugin.py │ ├── serializer.py │ ├── v2.py │ └── v3.py ├── hacking │ ├── __init__.py │ └── checks.py ├── http_basic.py ├── identity │ ├── __init__.py │ ├── access.py │ ├── base.py │ ├── generic │ │ ├── __init__.py │ │ ├── base.py │ │ ├── password.py │ │ └── token.py │ ├── v2.py │ └── v3 │ │ ├── __init__.py │ │ ├── application_credential.py │ │ ├── base.py │ │ ├── federation.py │ │ ├── k2k.py │ │ ├── multi_factor.py │ │ ├── oauth2_client_credential.py │ │ ├── oauth2_mtls_client_credential.py │ │ ├── oidc.py │ │ ├── password.py │ │ ├── receipt.py │ │ ├── token.py │ │ ├── tokenless_auth.py │ │ └── totp.py ├── loading │ ├── __init__.py │ ├── _plugins │ │ ├── __init__.py │ │ ├── admin_token.py │ │ ├── http_basic.py │ │ ├── identity │ │ │ ├── __init__.py │ │ │ ├── generic.py │ │ │ ├── v2.py │ │ │ └── v3.py │ │ └── noauth.py │ ├── _utils.py │ ├── adapter.py │ ├── base.py │ ├── cli.py │ ├── conf.py │ ├── identity.py │ ├── opts.py │ └── session.py ├── noauth.py ├── plugin.py ├── py.typed ├── service_token.py ├── session.py ├── tests │ ├── __init__.py │ └── unit │ │ ├── __init__.py │ │ ├── access │ │ ├── __init__.py │ │ ├── test_v2_access.py │ │ ├── test_v2_service_catalog.py │ │ ├── test_v3_access.py │ │ └── test_v3_service_catalog.py │ │ ├── client_fixtures.py │ │ ├── data │ │ ├── README │ │ ├── keystone_v2_sample_request.json │ │ ├── keystone_v2_sample_response.json │ │ ├── keystone_v3_sample_request.json │ │ ├── keystone_v3_sample_response.json │ │ ├── ksa_betamax_test_cassette.yaml │ │ ├── ksa_serializer_data.json │ │ └── test_pre_record_hook.json │ │ ├── exceptions │ │ ├── __init__.py │ │ └── test_exceptions.py │ │ ├── extras │ │ ├── __init__.py │ │ ├── kerberos │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── test_fedkerb_loading.py │ │ │ ├── test_kerberos_loading.py │ │ │ ├── test_mapped.py │ │ │ ├── test_v3.py │ │ │ └── utils.py │ │ ├── oauth1 │ │ │ ├── __init__.py │ │ │ ├── test_oauth1.py │ │ │ └── test_oauth1_loading.py │ │ └── saml2 │ │ │ ├── __init__.py │ │ │ ├── examples │ │ │ └── xml │ │ │ │ ├── ADFS_RequestSecurityTokenResponse.xml │ │ │ │ └── ADFS_fault.xml │ │ │ ├── fixtures │ │ │ ├── __init__.py │ │ │ └── templates │ │ │ │ ├── authn_request.xml │ │ │ │ ├── saml_assertion.xml │ │ │ │ └── soap_response.xml │ │ │ ├── test_auth_adfs.py │ │ │ ├── test_auth_saml2.py │ │ │ └── utils.py │ │ ├── identity │ │ ├── __init__.py │ │ ├── test_access.py │ │ ├── test_identity_common.py │ │ ├── test_identity_v2.py │ │ ├── test_identity_v3.py │ │ ├── test_identity_v3_federation.py │ │ ├── test_identity_v3_oidc.py │ │ ├── test_password.py │ │ ├── test_token.py │ │ ├── test_tokenless_auth.py │ │ └── utils.py │ │ ├── k2k_fixtures.py │ │ ├── keystoneauth_fixtures.py │ │ ├── loading │ │ ├── __init__.py │ │ ├── test_adapter.py │ │ ├── test_cli.py │ │ ├── test_conf.py │ │ ├── test_entry_points.py │ │ ├── test_fixtures.py │ │ ├── test_generic.py │ │ ├── test_loading.py │ │ ├── test_opts.py │ │ ├── test_session.py │ │ ├── test_v3.py │ │ └── utils.py │ │ ├── matchers.py │ │ ├── oidc_fixtures.py │ │ ├── test_betamax_fixture.py │ │ ├── test_betamax_hooks.py │ │ ├── test_betamax_serializer.py │ │ ├── test_discovery.py │ │ ├── test_fair_sempahore.py │ │ ├── test_fixtures.py │ │ ├── test_hacking_checks.py │ │ ├── test_http_basic.py │ │ ├── test_matchers.py │ │ ├── test_noauth.py │ │ ├── test_service_token.py │ │ ├── test_session.py │ │ ├── test_token_endpoint.py │ │ ├── test_utils.py │ │ └── utils.py └── token_endpoint.py ├── pyproject.toml ├── releasenotes ├── notes │ ├── .placeholder │ ├── 1583780-700f99713e06324e.yaml │ ├── add-oidc-client-credentials-2be065926ba4b849.yaml │ ├── add-oidc-discovery-document-support-b07fe54f83286d62.yaml │ ├── add-otp-support-to-v3oidcpassword-plugin-520160b14e1fcc57.yaml │ ├── add-prompt-to-opt-d083acc357a7f07b.yaml │ ├── add-totp-auth-plugin-0650d220899c25b7.yaml │ ├── add-typing-617a487a60de0b86.yaml │ ├── additional-headers-f2d16f85f5abe942.yaml │ ├── allow_version_hack-flag-9b53b72d9b084c04.yaml │ ├── api-sig-error-guideline-handler.yaml │ ├── basic-http-auth-45bea4298209df75.yaml │ ├── bp-application-credentials-416a1f8bb2311e04.yaml │ ├── bp-oauth2-client-credentials-ext-06271700d4f33a7e.yaml │ ├── bp-support-oauth2-mtls-177cda05265ae65c.yaml │ ├── bp-system-scope-29e9c597039ddb1e.yaml │ ├── bug-1582774-49af731b6dfc6f2f.yaml │ ├── bug-1614688-c4a1bd54f4ba5644.yaml │ ├── bug-1616105-cc8b85eb056e99e2.yaml │ ├── bug-1654847-acdf9543158329ec.yaml │ ├── bug-1689424-set-adfspassword-endpointreference-f186d84a54007b09.yaml │ ├── bug-1733052-1b4af3b3fe1b05bb.yaml │ ├── bug-1766235wq-0de60d0f996c6bfb.yaml │ ├── bug-1839748-5d8dfc99c43aaefc.yaml │ ├── bug-1840235-ef2946d149ac329c.yaml │ ├── bug-1876317-1db97d1b12a3e4b4.yaml │ ├── bug-1998366-27cd486b46fb56b0.yaml │ ├── bug-2053965-b9717c6a8c058956.yaml │ ├── cache-trailing-slash-3663c86cd9754379.yaml │ ├── cleanup-session-on-delete-1ed6177d4c5c1f83.yaml │ ├── client-side-rate-limiting-dec43fc9b54f5b70.yaml │ ├── collect-timing-85f007f0d86c8b26.yaml │ ├── drop-oidc-grant_type-parameter-79ca58f56238a615.yaml │ ├── drop-py-2-7-f90c67a5db0dfeb8.yaml │ ├── drop-python-3-6-and-3-7-c407d5898c5eafec.yaml │ ├── drop-python-3.5-362bb9d47f830353.yaml │ ├── drop-python-39-cb01f8d8ce6dc278.yaml │ ├── drop-python38-cb0b045f67bf8a1b.yaml │ ├── drops-url-parameters-on-redirect-13951b4a4c830d0f.yaml │ ├── expose-endpoint-status-6195a6b76d8a8de8.yaml │ ├── filter-versions-service-type-763af68092344b7a.yaml │ ├── fix-get-all-version-data-a01ee58524755b9b.yaml │ ├── get-auth-ref-7418e13bd0942060.yaml │ ├── global_request_id-per-request-bd66c7e0f1a71d9f.yaml │ ├── improve-http-error-handling.yaml │ ├── ironic-discovery-fe41793ef97027bf.yaml │ ├── ironic-microversions-a69bf92ab21f0cf5.yaml │ ├── ksa_2.2.0-81145229d4b43043.yaml │ ├── microversion-header-support-901acd820a21d788.yaml │ ├── noauth-discovery-c26d82a32c36d41d.yaml │ ├── none-auth-dab13ab9af6f5c86.yaml │ ├── oslo-config-split-loggers-6bda266d657fe921.yaml │ ├── retries-limit-dbaedcb3207934ae.yaml │ ├── retries-options-99e4dbc240941557.yaml │ ├── retry-authenticated-discovery-19c4354ff983f507.yaml │ ├── retry-delay-68d0c0a1dffcf2fd.yaml │ ├── serice-type-aliases-249454829c57f39a.yaml │ ├── status-code-retries-75052a43efa4edb2.yaml │ ├── support-api-wg-discovery-2cb4b0186619e124.yaml │ ├── user-agent-generation-b069100508c06177.yaml │ └── version-between-b4b0bcf4cecfb9e4.yaml └── source │ ├── 2023.1.rst │ ├── 2023.2.rst │ ├── 2024.1.rst │ ├── 2024.2.rst │ ├── 2025.1.rst │ ├── _static │ └── .placeholder │ ├── _templates │ └── .placeholder │ ├── conf.py │ ├── index.rst │ ├── mitaka.rst │ ├── newton.rst │ ├── ocata.rst │ ├── pike.rst │ ├── queens.rst │ ├── rocky.rst │ ├── stein.rst │ ├── train.rst │ ├── unreleased.rst │ ├── ussuri.rst │ ├── victoria.rst │ ├── wallaby.rst │ ├── xena.rst │ ├── yoga.rst │ └── zed.rst ├── requirements.txt ├── setup.cfg ├── setup.py ├── test-requirements.txt └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = keystoneauth1 4 | omit = keystoneauth1/tests/* 5 | 6 | [report] 7 | ignore_errors = True 8 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # You can configure git to automatically use this file with the following config: 2 | # git config --global blame.ignoreRevsFile .git-blame-ignore-revs 3 | 4 | 127d7be2b73cdc30ad388e992edba371f0c19f26 # Apply ruff, ruff-format 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | .testrepository 3 | .stestr 4 | subunit.log 5 | .venv 6 | *,cover 7 | cover 8 | *.pyc 9 | .idea 10 | *.sw? 11 | *.egg 12 | *~ 13 | .tox 14 | AUTHORS 15 | ChangeLog 16 | build 17 | dist 18 | keystoneauth1.egg-info 19 | doc/source/api 20 | # Development environment files 21 | .project 22 | .pydevproject 23 | # Temporary files created during test, but not removed 24 | examples/pki/certs/tmp* 25 | # Files created by releasenotes build 26 | releasenotes/build 27 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.opendev.org 3 | port=29418 4 | project=openstack/keystoneauth.git 5 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | # Format is: 2 | # 3 | # 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v5.0.0 5 | hooks: 6 | - id: trailing-whitespace 7 | - id: mixed-line-ending 8 | args: ['--fix', 'lf'] 9 | exclude: '.*\.(svg)$' 10 | - id: check-byte-order-marker 11 | - id: check-executables-have-shebangs 12 | - id: check-merge-conflict 13 | - id: debug-statements 14 | - id: check-yaml 15 | files: .*\.(yaml|yml)$ 16 | exclude: '^zuul.d/.*$' 17 | - repo: https://github.com/astral-sh/ruff-pre-commit 18 | rev: v0.11.8 19 | hooks: 20 | - id: ruff 21 | args: ['--fix', '--unsafe-fixes'] 22 | - id: ruff-format 23 | - repo: https://github.com/PyCQA/bandit 24 | rev: 1.8.3 25 | hooks: 26 | - id: bandit 27 | # We ignore the following: 28 | # B110: except: pass 29 | args: ['-x', 'tests', '-s', 'B110'] 30 | - repo: https://opendev.org/openstack/hacking 31 | rev: 7.0.0 32 | hooks: 33 | - id: hacking 34 | additional_dependencies: 35 | - flake8-import-order~=0.18.2 36 | exclude: '^(doc|releasenotes|tools)/.*$' 37 | - repo: https://github.com/pre-commit/mirrors-mypy 38 | rev: v1.15.0 39 | hooks: 40 | - id: mypy 41 | additional_dependencies: 42 | - types-PyYAML 43 | - types-requests 44 | - types-simplejson 45 | - types-lxml 46 | - iso8601 47 | # keep this in-sync with '[mypy] exclude' in 'setup.cfg' 48 | exclude: | 49 | (?x)( 50 | doc/.* 51 | | examples/.* 52 | | releasenotes/.* 53 | ) 54 | -------------------------------------------------------------------------------- /.stestr.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | test_path=./keystoneauth1/tests/unit 3 | top_dir=./ 4 | -------------------------------------------------------------------------------- /.zuul.yaml: -------------------------------------------------------------------------------- 1 | - project: 2 | templates: 3 | - check-requirements 4 | - lib-forward-testing-python3 5 | - openstack-python3-jobs 6 | - openstacksdk-functional-tips 7 | - openstacksdk-tox-tips 8 | - osc-tox-unit-tips 9 | - publish-openstack-docs-pti 10 | - release-notes-jobs-python3 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | If you would like to contribute to the development of OpenStack, 2 | you must follow the steps documented at: 3 | 4 | https://docs.openstack.org/infra/manual/developers.html 5 | 6 | If you already have a good understanding of how the system works 7 | and your OpenStack accounts are set up, you can skip to the 8 | development workflow section of this documentation to learn how 9 | changes to OpenStack should be submitted for review via the 10 | Gerrit tool: 11 | 12 | https://docs.openstack.org/infra/manual/developers.html#development-workflow 13 | 14 | Pull requests submitted through GitHub will be ignored. 15 | 16 | Bugs should be filed on Launchpad, not GitHub: 17 | 18 | https://bugs.launchpad.net/keystoneauth 19 | -------------------------------------------------------------------------------- /HACKING.rst: -------------------------------------------------------------------------------- 1 | Keystone Style Commandments 2 | =========================== 3 | 4 | - Step 1: Read the OpenStack Style Commandments 5 | https://docs.openstack.org/hacking/latest/ 6 | - Step 2: Read on 7 | 8 | Exceptions 9 | ---------- 10 | 11 | When dealing with exceptions from underlying libraries, translate those 12 | exceptions to an instance or subclass of ClientException. 13 | 14 | ======= 15 | Testing 16 | ======= 17 | 18 | keystoneauth uses testtools and stestr for its unittest suite 19 | and its test runner. Basic workflow around our use of tox and stestr can 20 | be found at https://wiki.openstack.org/testr. If you'd like to learn more 21 | in depth: 22 | 23 | https://testtools.readthedocs.io/en/latest/ 24 | https://stestr.readthedocs.io/en/latest/ 25 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Team and repository tags 3 | ======================== 4 | 5 | .. image:: https://governance.openstack.org/tc/badges/keystoneauth.svg 6 | :target: https://governance.openstack.org/tc/reference/tags/index.html 7 | 8 | .. Change things from this point on 9 | 10 | ============ 11 | keystoneauth 12 | ============ 13 | 14 | .. image:: https://img.shields.io/pypi/v/keystoneauth1.svg 15 | :target:https://pypi.org/project/keystoneauth1 16 | :alt: Latest Version 17 | 18 | .. image:: https://img.shields.io/pypi/dm/keystoneauth1.svg 19 | :target: https://pypi.org/project/keystoneauth1/ 20 | :alt: Downloads 21 | 22 | This package contains tools for authenticating to an OpenStack-based cloud. 23 | These tools include: 24 | 25 | * Authentication plugins (password, token, and federation based) 26 | * Discovery mechanisms to determine API version support 27 | * A session that is used to maintain client settings across requests (based on 28 | the requests Python library) 29 | 30 | Further information: 31 | 32 | * Free software: Apache license 33 | * Documentation: https://docs.openstack.org/keystoneauth/latest/ 34 | * Source: https://opendev.org/openstack/keystoneauth 35 | * Bugs: https://bugs.launchpad.net/keystoneauth 36 | * Release notes: https://docs.openstack.org/releasenotes/keystoneauth/ 37 | -------------------------------------------------------------------------------- /bindep.txt: -------------------------------------------------------------------------------- 1 | # This is a cross-platform list tracking distribution packages needed for install and tests; 2 | # see https://docs.openstack.org/infra/bindep/ for additional information. 3 | 4 | build-essential [platform:dpkg test] 5 | python3-dev [platform:dpkg test] 6 | python3-devel [platform:rpm test] 7 | libkrb5-dev [platform:dpkg test] 8 | krb5-devel [platform:rpm test] 9 | libxml2-dev [platform:dpkg] 10 | libxml2-devel [platform:rpm] 11 | libxslt-devel [platform:rpm] 12 | libxslt1-dev [platform:dpkg] 13 | zlib-devel [platform:rpm] 14 | zlib1g-dev [platform:dpkg] 15 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXSOURCE = source 8 | PAPER = 9 | BUILDDIR = build 10 | 11 | # Internal variables. 12 | PAPEROPT_a4 = -D latex_paper_size=a4 13 | PAPEROPT_letter = -D latex_paper_size=letter 14 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SPHINXSOURCE) 15 | 16 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 17 | 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 27 | @echo " changes to make an overview of all changed/added/deprecated items" 28 | @echo " linkcheck to check all external links for integrity" 29 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 30 | 31 | clean: 32 | -rm -rf $(BUILDDIR)/* 33 | 34 | html: 35 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 36 | @echo 37 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 38 | 39 | dirhtml: 40 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 43 | 44 | pickle: 45 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 46 | @echo 47 | @echo "Build finished; now you can process the pickle files." 48 | 49 | json: 50 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 51 | @echo 52 | @echo "Build finished; now you can process the JSON files." 53 | 54 | htmlhelp: 55 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 56 | @echo 57 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 58 | ".hhp project file in $(BUILDDIR)/htmlhelp." 59 | 60 | qthelp: 61 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 62 | @echo 63 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 64 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 65 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/keystoneauth.qhcp" 66 | @echo "To view the help file:" 67 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/keystoneauth.qhc" 68 | 69 | latex: 70 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 71 | @echo 72 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 73 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 74 | "run these through (pdf)latex." 75 | 76 | changes: 77 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 78 | @echo 79 | @echo "The overview file is in $(BUILDDIR)/changes." 80 | 81 | linkcheck: 82 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 83 | @echo 84 | @echo "Link check complete; look for any errors in the above output " \ 85 | "or in $(BUILDDIR)/linkcheck/output.txt." 86 | 87 | doctest: 88 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 89 | @echo "Testing of doctests in the sources finished, look at the " \ 90 | "results in $(BUILDDIR)/doctest/output.txt." 91 | -------------------------------------------------------------------------------- /doc/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/doc/ext/__init__.py -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | # For generationg sphinx documentation 2 | openstackdocstheme>=2.2.1 # Apache-2.0 3 | reno>=3.1.0 # Apache-2.0 4 | sphinx>=2.0.0 # BSD 5 | sphinxcontrib-apidoc>=0.2.0 # BSD 6 | 7 | # For autodoc builds 8 | fixtures>=3.0.0 # Apache-2.0/BSD 9 | betamax>=0.7.0 # Apache-2.0 10 | oslo.config>=5.2.0 # Apache-2.0 11 | oslo.utils>=3.33.0 # Apache-2.0 12 | requests-mock>=1.2.0 # Apache-2.0 13 | lxml>=4.2.0 # BSD 14 | oauthlib>=0.6.2 # BSD 15 | -------------------------------------------------------------------------------- /doc/source/extras.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | Extras 3 | ====== 4 | 5 | The extensibility of keystoneauth plugins is purposefully designed to allow a 6 | range of different authentication mechanisms that don't have to reside in the 7 | upstream packages. There are however a number of plugins that upstream supports 8 | that involve additional dependencies that the keystoneauth package cannot 9 | depend upon directly. 10 | 11 | To get around this we utilize setuptools `extras dependencies `_ for additional 12 | plugins. To use a plugin like the kerberos plugin that has additional 13 | dependencies you must install the additional dependencies like:: 14 | 15 | pip install keystoneauth1[kerberos] 16 | 17 | By convention (not a requirement) extra plugins have a module located in the 18 | keystoneauth1.extras module with the same name as the dependency. eg:: 19 | 20 | from keystoneauth1.extras import kerberos 21 | 22 | There is no keystoneauth specific check that the correct dependencies are 23 | installed for accessing a module. You would expect to see standard python 24 | ImportError when the required dependencies are not found. 25 | 26 | Examples 27 | ======== 28 | 29 | All extras plugins follow the pattern: 30 | 31 | 1. import plugin module 32 | 2. instantiate the plugin 33 | 3. call get_token method of the plugin passing it a session object 34 | to get a token 35 | 36 | Kerberos 37 | -------- 38 | 39 | Get domain-scoped token using 40 | :py:class:`~keystoneauth1.extras.kerberos.Kerberos`:: 41 | 42 | from keystoneauth1.extras import kerberos 43 | from keystoneauth1 import session 44 | 45 | plugin = kerberos.Kerberos('http://example.com:5000/v3') 46 | sess = session.Session(plugin) 47 | token = plugin.get_token(sess) 48 | 49 | Get unscoped federated token:: 50 | 51 | from keystoneauth1.extras import kerberos 52 | from keystoneauth1 import session 53 | 54 | plugin = kerberos.MappedKerberos( 55 | auth_url='http://example.com:5000/v3', protocol='example_protocol', 56 | identity_provider='example_identity_provider') 57 | 58 | sess = session.Session() 59 | token = plugin.get_token(sess) 60 | 61 | Get project scoped federated token:: 62 | 63 | from keystoneauth1.extras import kerberos 64 | from keystoneauth1 import session 65 | 66 | plugin = kerberos.MappedKerberos( 67 | auth_url='http://example.com:5000/v3', protocol='example_protocol', 68 | identity_provider='example_identity_provider', 69 | project_id='example_project_id') 70 | 71 | sess = session.Session() 72 | token = plugin.get_token(sess) 73 | project_id = plugin.get_project_id(sess) 74 | -------------------------------------------------------------------------------- /doc/source/images/graphs_authComp.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | AuthComp 11 | 12 | 13 | AuthComp 14 | 15 | Auth 16 | Component 17 | 18 | 19 | 20 | AuthComp->Reject 21 | 22 | 23 | Reject 24 | Unauthenticated 25 | Requests 26 | 27 | 28 | Service 29 | 30 | OpenStack 31 | Service 32 | 33 | 34 | AuthComp->Service 35 | 36 | 37 | Forward 38 | Authenticated 39 | Requests 40 | 41 | 42 | 43 | Start->AuthComp 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | Common Authentication Library for OpenStack Clients 2 | =================================================== 3 | 4 | Keystoneauth provides a standard way to do authentication and service requests 5 | within the OpenStack ecosystem. It is designed for use in conjunction with the 6 | existing OpenStack clients and for simplifying the process of writing new 7 | clients. 8 | 9 | Contents 10 | -------- 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | 15 | using-sessions 16 | authentication-plugins 17 | plugin-options 18 | 19 | extras 20 | migrating 21 | 22 | api/modules 23 | 24 | Release Notes 25 | ------------- 26 | 27 | `Release Notes`_ 28 | 29 | .. _Release Notes: https://docs.openstack.org/releasenotes/keystoneauth/ 30 | 31 | Contributing 32 | ------------ 33 | 34 | Code is hosted `on opendev.org`_. Submit bugs to the Keystone project on 35 | `Launchpad`_. Submit code to the ``openstack/keystoneauth`` project 36 | using `Gerrit`_. 37 | 38 | .. _on opendev.org: https://opendev.org/openstack/keystoneauth 39 | .. _Launchpad: https://launchpad.net/keystoneauth 40 | .. _Gerrit: https://docs.openstack.org/infra/manual/developers.html#development-workflow 41 | 42 | Run tests with ``tox``. 43 | 44 | Indices and tables 45 | ------------------ 46 | 47 | * :ref:`genindex` 48 | * :ref:`modindex` 49 | * :ref:`search` 50 | -------------------------------------------------------------------------------- /keystoneauth1/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import pbr.version 14 | 15 | 16 | __version__ = pbr.version.VersionInfo('keystoneauth1').version_string() 17 | -------------------------------------------------------------------------------- /keystoneauth1/access/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.access.access import * # noqa 14 | 15 | 16 | __all__ = ( # noqa: F405 17 | 'AccessInfo', 18 | 'AccessInfoV2', 19 | 'AccessInfoV3', 20 | 'create', 21 | ) 22 | -------------------------------------------------------------------------------- /keystoneauth1/access/service_providers.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | # you may not use this file except in compliance with the License. 3 | # You may obtain a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | 14 | from keystoneauth1.access import types 15 | from keystoneauth1 import exceptions 16 | 17 | 18 | class ServiceProviders: 19 | """Helper methods for dealing with Service Providers.""" 20 | 21 | def __init__(self, service_providers: list[types.ServiceProviderV3]): 22 | self._service_providers = { 23 | sp['id']: sp for sp in service_providers if 'id' in sp 24 | } 25 | 26 | @classmethod 27 | def from_token(cls, token: types.TokenResponseV3) -> 'ServiceProviders': 28 | if 'token' not in token: 29 | raise ValueError( 30 | 'Token format does not support service providers.' 31 | ) 32 | 33 | return cls(token['token'].get('service_providers', [])) 34 | 35 | def _get_service_provider(self, sp_id: str) -> types.ServiceProviderV3: 36 | try: 37 | return self._service_providers[sp_id] 38 | except KeyError: 39 | raise exceptions.ServiceProviderNotFound(sp_id) 40 | 41 | def get_sp_url(self, sp_id: str) -> str: 42 | return self._get_service_provider(sp_id)['sp_url'] 43 | 44 | def get_auth_url(self, sp_id: str) -> str: 45 | return self._get_service_provider(sp_id)['auth_url'] 46 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1.exceptions.auth import * # noqa 15 | from keystoneauth1.exceptions.auth_plugins import * # noqa 16 | from keystoneauth1.exceptions.base import * # noqa 17 | from keystoneauth1.exceptions.catalog import * # noqa 18 | from keystoneauth1.exceptions.connection import * # noqa 19 | from keystoneauth1.exceptions.discovery import * # noqa 20 | from keystoneauth1.exceptions.http import * # noqa 21 | from keystoneauth1.exceptions.oidc import * # noqa 22 | from keystoneauth1.exceptions.response import * # noqa 23 | from keystoneauth1.exceptions.service_providers import * # noqa 24 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/auth.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import requests 14 | 15 | from keystoneauth1 import _utils as utils 16 | from keystoneauth1.exceptions import base 17 | 18 | 19 | class AuthorizationFailure(base.ClientException): 20 | message = "Cannot authorize API client." 21 | 22 | 23 | class MissingAuthMethods(base.ClientException): 24 | message = "Not all required auth rules were satisfied" 25 | 26 | def __init__(self, response: requests.Response): 27 | self.response = response 28 | self.receipt = response.headers.get("Openstack-Auth-Receipt") 29 | body = response.json() 30 | self.methods = body['receipt']['methods'] 31 | self.required_auth_methods = body['required_auth_methods'] 32 | self.expires_at = utils.parse_isotime(body['receipt']['expires_at']) 33 | message = f"{self.message}: {self.required_auth_methods}" 34 | super().__init__(message) 35 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/auth_plugins.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import typing as ty 14 | 15 | from keystoneauth1.exceptions import base 16 | 17 | if ty.TYPE_CHECKING: 18 | from keystoneauth1 import loading 19 | 20 | 21 | __all__ = ( 22 | 'AuthPluginException', 23 | 'MissingAuthPlugin', 24 | 'NoMatchingPlugin', 25 | 'UnsupportedParameters', 26 | 'OptionError', 27 | 'MissingRequiredOptions', 28 | ) 29 | 30 | 31 | class AuthPluginException(base.ClientException): 32 | message = "Unknown error with authentication plugins." 33 | 34 | 35 | class MissingAuthPlugin(AuthPluginException): 36 | message = "An authenticated request is required but no plugin available." 37 | 38 | 39 | class NoMatchingPlugin(AuthPluginException): 40 | """No auth plugins could be created from the parameters provided. 41 | 42 | :param str name: The name of the plugin that was attempted to load. 43 | 44 | .. py:attribute:: name 45 | 46 | The name of the plugin that was attempted to load. 47 | """ 48 | 49 | def __init__(self, name: str): 50 | self.name = name 51 | msg = f'The plugin {name} could not be found' 52 | super().__init__(msg) 53 | 54 | 55 | class UnsupportedParameters(AuthPluginException): 56 | """A parameter that was provided or returned is not supported. 57 | 58 | :param list(str) names: Names of the unsupported parameters. 59 | 60 | .. py:attribute:: names 61 | 62 | Names of the unsupported parameters. 63 | """ 64 | 65 | def __init__(self, names: ty.Sequence[str]): 66 | self.names = names 67 | 68 | m = 'The following parameters were given that are unsupported: %s' 69 | super().__init__(m % ', '.join(self.names)) 70 | 71 | 72 | class OptionError(AuthPluginException): 73 | """A requirement of this plugin loader was not met. 74 | 75 | This error can be raised by a specific plugin loader during the 76 | load_from_options stage to indicate a parameter problem that can not be 77 | handled by the generic options loader. 78 | 79 | The intention here is that a plugin can do checks like if a name parameter 80 | is provided then a domain parameter must also be provided, but that Opt 81 | checking doesn't handle. 82 | """ 83 | 84 | 85 | class MissingRequiredOptions(OptionError): 86 | """One or more required options were not provided. 87 | 88 | :param list(keystoneauth1.loading.Opt) options: Missing options. 89 | 90 | .. py:attribute:: options 91 | 92 | List of the missing options. 93 | """ 94 | 95 | def __init__(self, options: ty.Sequence['loading.Opt']): 96 | self.options = options 97 | 98 | names = ", ".join(o.dest for o in options) 99 | m = 'Auth plugin requires parameters which were not given: %s' 100 | super().__init__(m % names) 101 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/base.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | __all__ = ('ClientException',) 15 | 16 | 17 | class ClientException(Exception): 18 | """The base exception for everything to do with clients.""" 19 | 20 | message = "ClientException" 21 | 22 | def __init__(self, message: str | None = None): 23 | self.message = message or self.message 24 | super().__init__(self.message) 25 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/catalog.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1.exceptions import base 15 | 16 | __all__ = ('CatalogException', 'EmptyCatalog', 'EndpointNotFound') 17 | 18 | 19 | class CatalogException(base.ClientException): 20 | message = "Unknown error with service catalog." 21 | 22 | 23 | class EndpointNotFound(CatalogException): 24 | message = "Could not find requested endpoint in Service Catalog." 25 | 26 | 27 | class EmptyCatalog(EndpointNotFound): 28 | message = "The service catalog is empty." 29 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/connection.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.exceptions import base 14 | 15 | 16 | __all__ = ( 17 | 'ConnectionError', 18 | 'ConnectTimeout', 19 | 'ConnectFailure', 20 | 'SSLError', 21 | 'RetriableConnectionFailure', 22 | 'UnknownConnectionError', 23 | ) 24 | 25 | 26 | class RetriableConnectionFailure(Exception): 27 | """A mixin class that implies you can retry the most recent request.""" 28 | 29 | pass 30 | 31 | 32 | class ConnectionError(base.ClientException): 33 | message = "Cannot connect to API service." 34 | 35 | 36 | class ConnectTimeout(ConnectionError, RetriableConnectionFailure): 37 | message = "Timed out connecting to service." 38 | 39 | 40 | class ConnectFailure(ConnectionError, RetriableConnectionFailure): 41 | message = "Connection failure that may be retried." 42 | 43 | 44 | class SSLError(ConnectionError): 45 | message = "An SSL error occurred." 46 | 47 | 48 | class UnknownConnectionError(ConnectionError): 49 | """An error was encountered but we don't know what it is.""" 50 | 51 | def __init__(self, msg: str, original: Exception): 52 | super().__init__(msg) 53 | self.original = original 54 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/discovery.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | import os_service_types 15 | 16 | from keystoneauth1.exceptions import base 17 | 18 | _SERVICE_TYPES = os_service_types.ServiceTypes() 19 | 20 | 21 | __all__ = ( 22 | 'DiscoveryFailure', 23 | 'ImpliedVersionMismatch', 24 | 'ImpliedMinVersionMismatch', 25 | 'ImpliedMaxVersionMismatch', 26 | 'VersionNotAvailable', 27 | ) 28 | 29 | _PARSED_VERSION_T = tuple[int | float, ...] 30 | 31 | 32 | class DiscoveryFailure(base.ClientException): 33 | message = "Discovery of client versions failed." 34 | 35 | 36 | class VersionNotAvailable(DiscoveryFailure): 37 | message = "Discovery failed. Requested version is not available." 38 | 39 | 40 | class ImpliedVersionMismatch(ValueError): 41 | label = 'version' 42 | 43 | def __init__( 44 | self, service_type: str, implied: _PARSED_VERSION_T, given: str 45 | ): 46 | super().__init__( 47 | f"service_type {service_type} was given which implies major API " 48 | f"version {str(implied[0])} but {self.label} of {given} was also " 49 | f"given. Please update your code to use the official service_type " 50 | f"{_SERVICE_TYPES.get_service_type(service_type)}." 51 | ) 52 | 53 | 54 | class ImpliedMinVersionMismatch(ImpliedVersionMismatch): 55 | label = 'min_version' 56 | 57 | 58 | class ImpliedMaxVersionMismatch(ImpliedVersionMismatch): 59 | label = 'max_version' 60 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/oidc.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1.exceptions import auth_plugins 15 | 16 | __all__ = ( 17 | 'InvalidDiscoveryEndpoint', 18 | 'InvalidOidcDiscoveryDocument', 19 | 'OidcAccessTokenEndpointNotFound', 20 | 'OidcAuthorizationEndpointNotFound', 21 | 'OidcInvalidCodeChallengeMethod', 22 | 'OidcPluginNotSupported', 23 | ) 24 | 25 | 26 | class InvalidDiscoveryEndpoint(auth_plugins.AuthPluginException): 27 | message = "OpenID Connect Discovery Document endpoint not set." 28 | 29 | 30 | class InvalidOidcDiscoveryDocument(auth_plugins.AuthPluginException): 31 | message = "OpenID Connect Discovery Document is not valid JSON." 32 | 33 | 34 | class OidcAccessTokenEndpointNotFound(auth_plugins.AuthPluginException): 35 | message = "OpenID Connect access token endpoint not provided." 36 | 37 | 38 | class OidcAuthorizationEndpointNotFound(auth_plugins.AuthPluginException): 39 | message = "OpenID Connect authorization endpoint not provided." 40 | 41 | 42 | class OidcDeviceAuthorizationEndpointNotFound( 43 | auth_plugins.AuthPluginException 44 | ): 45 | message = "OpenID Connect device authorization endpoint not provided." 46 | 47 | 48 | class OidcDeviceAuthorizationTimeOut(auth_plugins.AuthPluginException): 49 | message = "Timeout for OpenID Connect device authorization." 50 | 51 | 52 | class OidcInvalidCodeChallengeMethod(auth_plugins.AuthPluginException): 53 | message = "Invalid code challenge method." 54 | 55 | 56 | class OidcPluginNotSupported(auth_plugins.AuthPluginException): 57 | message = "OpenID Connect grant type not supported by provider." 58 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/response.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import requests 14 | 15 | from keystoneauth1.exceptions import base 16 | 17 | 18 | __all__ = ('InvalidResponse',) 19 | 20 | 21 | class InvalidResponse(base.ClientException): 22 | message = "Invalid response from server." 23 | 24 | def __init__(self, response: requests.Response): 25 | super().__init__() 26 | self.response = response 27 | -------------------------------------------------------------------------------- /keystoneauth1/exceptions/service_providers.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.exceptions import base 14 | 15 | __all__ = ('ServiceProviderNotFound',) 16 | 17 | 18 | class ServiceProviderNotFound(base.ClientException): 19 | """A Service Provider cannot be found.""" 20 | 21 | def __init__(self, sp_id: str): 22 | self.sp_id = sp_id 23 | msg = f'The Service Provider {sp_id} could not be found' 24 | super().__init__(msg) 25 | -------------------------------------------------------------------------------- /keystoneauth1/extras/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | # NOTE(jamielennox): This directory is designed to reflect the dependency 14 | # extras in the setup.cfg file. If you create an additional dependency section 15 | # like 'kerberos' in the setup.cfg it is expected that there be a kerberos 16 | # package here that can be imported. 17 | # 18 | # e.g. from keystoneauth1.extras import kerberos 19 | 20 | pass 21 | -------------------------------------------------------------------------------- /keystoneauth1/extras/_saml2/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.extras._saml2 import v3 14 | 15 | _V3_SAML2_AVAILABLE = v3._SAML2_AVAILABLE 16 | _V3_ADFS_AVAILABLE = v3._ADFS_AVAILABLE 17 | 18 | V3Saml2Password = v3.Saml2Password 19 | V3ADFSPassword = v3.ADFSPassword 20 | 21 | 22 | __all__ = ('V3Saml2Password', 'V3ADFSPassword') 23 | -------------------------------------------------------------------------------- /keystoneauth1/extras/_saml2/_loading.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1.extras import _saml2 15 | from keystoneauth1 import loading 16 | from keystoneauth1.loading import opts 17 | 18 | 19 | class Saml2Password(loading.BaseFederationLoader[_saml2.V3Saml2Password]): 20 | @property 21 | def plugin_class(self) -> type[_saml2.V3Saml2Password]: 22 | return _saml2.V3Saml2Password 23 | 24 | @property 25 | def available(self) -> bool: 26 | return _saml2._V3_SAML2_AVAILABLE 27 | 28 | def get_options(self) -> list[opts.Opt]: 29 | options = super().get_options() 30 | 31 | options.extend( 32 | [ 33 | loading.Opt( 34 | 'identity-provider-url', 35 | required=True, 36 | help=( 37 | 'An Identity Provider URL, where the SAML2 ' 38 | 'authentication request will be sent.' 39 | ), 40 | ), 41 | loading.Opt('username', help='Username', required=True), 42 | loading.Opt( 43 | 'password', secret=True, help='Password', required=True 44 | ), 45 | ] 46 | ) 47 | 48 | return options 49 | 50 | 51 | class ADFSPassword(loading.BaseFederationLoader[_saml2.V3ADFSPassword]): 52 | @property 53 | def plugin_class(self) -> type[_saml2.V3ADFSPassword]: 54 | return _saml2.V3ADFSPassword 55 | 56 | @property 57 | def available(self) -> bool: 58 | return _saml2._V3_ADFS_AVAILABLE 59 | 60 | def get_options(self) -> list[opts.Opt]: 61 | options = super().get_options() 62 | 63 | options.extend( 64 | [ 65 | loading.Opt( 66 | 'identity-provider-url', 67 | required=True, 68 | help=( 69 | 'An Identity Provider URL, where the SAML ' 70 | 'authentication request will be sent.' 71 | ), 72 | ), 73 | loading.Opt( 74 | 'service-provider-endpoint', 75 | required=True, 76 | help="Service Provider's Endpoint", 77 | ), 78 | loading.Opt( 79 | 'service-provider-entity-id', 80 | required=True, 81 | help="Service Provider's SAML Entity ID", 82 | ), 83 | loading.Opt('username', help='Username', required=True), 84 | loading.Opt( 85 | 'password', secret=True, required=True, help='Password' 86 | ), 87 | ] 88 | ) 89 | 90 | return options 91 | -------------------------------------------------------------------------------- /keystoneauth1/extras/_saml2/v3/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.extras._saml2.v3 import adfs 14 | from keystoneauth1.extras._saml2.v3 import base 15 | from keystoneauth1.extras._saml2.v3 import saml2 16 | 17 | _SAML2_AVAILABLE = base.etree is not None and saml2.etree is not None 18 | _ADFS_AVAILABLE = base.etree is not None and adfs.etree is not None 19 | 20 | Saml2Password = saml2.Password 21 | ADFSPassword = adfs.Password 22 | 23 | __all__ = ('Saml2Password', 'ADFSPassword') 24 | -------------------------------------------------------------------------------- /keystoneauth1/extras/kerberos/_loading.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import typing as ty 14 | 15 | from keystoneauth1 import exceptions 16 | from keystoneauth1.extras import kerberos 17 | from keystoneauth1 import loading 18 | from keystoneauth1.loading import opts 19 | 20 | 21 | class Kerberos(loading.BaseV3Loader[kerberos.Kerberos]): 22 | @property 23 | def plugin_class(self) -> type[kerberos.Kerberos]: 24 | return kerberos.Kerberos 25 | 26 | @property 27 | def available(self) -> bool: 28 | return kerberos.requests_kerberos is not None 29 | 30 | def get_options(self) -> list[opts.Opt]: 31 | options = super().get_options() 32 | 33 | options.extend( 34 | [ 35 | loading.Opt( 36 | 'mutual-auth', 37 | required=False, 38 | default='optional', 39 | help='Configures Kerberos Mutual Authentication', 40 | ) 41 | ] 42 | ) 43 | 44 | return options 45 | 46 | def load_from_options(self, **kwargs: ty.Any) -> kerberos.Kerberos: 47 | if kwargs.get('mutual_auth'): 48 | value = kwargs['mutual_auth'] 49 | if value.lower() not in ['required', 'optional', 'disabled']: 50 | m = ( 51 | 'You need to provide a valid value for kerberos mutual ' 52 | 'authentication. It can be one of the following: ' 53 | '(required, optional, disabled)' 54 | ) 55 | raise exceptions.OptionError(m) 56 | 57 | return super().load_from_options(**kwargs) 58 | 59 | 60 | class MappedKerberos(loading.BaseFederationLoader[kerberos.MappedKerberos]): 61 | @property 62 | def plugin_class(self) -> type[kerberos.MappedKerberos]: 63 | return kerberos.MappedKerberos 64 | 65 | @property 66 | def available(self) -> bool: 67 | return kerberos.requests_kerberos is not None 68 | 69 | def get_options(self) -> list[opts.Opt]: 70 | options = super().get_options() 71 | 72 | options.extend( 73 | [ 74 | loading.Opt( 75 | 'mutual-auth', 76 | required=False, 77 | default='optional', 78 | help='Configures Kerberos Mutual Authentication', 79 | ) 80 | ] 81 | ) 82 | 83 | return options 84 | 85 | def load_from_options(self, **kwargs: ty.Any) -> kerberos.MappedKerberos: 86 | if kwargs.get('mutual_auth'): 87 | value = kwargs['mutual_auth'] 88 | if value.lower() not in ['required', 'optional', 'disabled']: 89 | m = ( 90 | 'You need to provide a valid value for kerberos mutual ' 91 | 'authentication. It can be one of the following: ' 92 | '(required, optional, disabled)' 93 | ) 94 | raise exceptions.OptionError(m) 95 | 96 | return super().load_from_options(**kwargs) 97 | -------------------------------------------------------------------------------- /keystoneauth1/extras/oauth1/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.extras.oauth1 import v3 14 | 15 | __all__ = ('V3OAuth1Method', 'V3OAuth1') 16 | 17 | 18 | V3OAuth1Method = v3.OAuth1Method 19 | V3OAuth1 = v3.OAuth1 20 | -------------------------------------------------------------------------------- /keystoneauth1/extras/oauth1/_loading.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1.extras.oauth1 import v3 15 | from keystoneauth1 import loading 16 | from keystoneauth1.loading import opts 17 | 18 | 19 | # NOTE(jamielennox): This is not a BaseV3Loader because we don't want to 20 | # include the scoping options like project-id in the option list 21 | class V3OAuth1(loading.BaseIdentityLoader[v3.OAuth1]): 22 | @property 23 | def plugin_class(self) -> type[v3.OAuth1]: 24 | return v3.OAuth1 25 | 26 | @property 27 | def available(self) -> bool: 28 | return v3.oauth1 is not None 29 | 30 | def get_options(self) -> list[opts.Opt]: 31 | options = super().get_options() 32 | 33 | options.extend( 34 | [ 35 | loading.Opt( 36 | 'consumer-key', required=True, help='OAuth Consumer ID/Key' 37 | ), 38 | loading.Opt( 39 | 'consumer-secret', 40 | required=True, 41 | help='OAuth Consumer Secret', 42 | ), 43 | loading.Opt( 44 | 'access-key', required=True, help='OAuth Access Key' 45 | ), 46 | loading.Opt( 47 | 'access-secret', required=True, help='OAuth Access Secret' 48 | ), 49 | ] 50 | ) 51 | 52 | return options 53 | -------------------------------------------------------------------------------- /keystoneauth1/fixture/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | """ 14 | Produce keystone compliant structures for use in testing. 15 | 16 | They are part of the public API because they may be relied upon to generate 17 | test tokens for other clients. However they should never be imported into the 18 | main client (keystoneauth or other). Because of this there may be dependencies 19 | from this module on libraries that are only available in testing. 20 | """ 21 | 22 | # flake8: noqa: F405 23 | 24 | from keystoneauth1.fixture.discovery import * # noqa 25 | from keystoneauth1.fixture import exception 26 | from keystoneauth1.fixture.plugin import * # noqa 27 | from keystoneauth1.fixture import v2 28 | from keystoneauth1.fixture import v3 29 | 30 | 31 | FixtureValidationError = exception.FixtureValidationError 32 | V2Token = v2.Token 33 | V3Token = v3.Token 34 | V3FederationToken = v3.V3FederationToken 35 | 36 | __all__ = ( 37 | 'DiscoveryList', 38 | 'FixtureValidationError', 39 | 'LoadingFixture', 40 | 'TestPlugin', 41 | 'V2Discovery', 42 | 'V3Discovery', 43 | 'V2Token', 44 | 'V3Token', 45 | 'V3FederationToken', 46 | 'VersionDiscovery', 47 | ) 48 | -------------------------------------------------------------------------------- /keystoneauth1/fixture/exception.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | class FixtureValidationError(Exception): 15 | """The token you created is not legitimate. 16 | 17 | The data contained in the token that was generated is not valid and would 18 | not have been returned from a keystone server. You should not do testing 19 | with this token. 20 | """ 21 | -------------------------------------------------------------------------------- /keystoneauth1/fixture/hooks.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | """Custom hooks for betamax and keystoneauth. 15 | 16 | Module providing a set of hooks specially designed for 17 | interacting with clouds and keystone authentication. 18 | 19 | :author: Yolanda Robla 20 | """ 21 | 22 | import json 23 | 24 | 25 | def mask_fixture_values(nested, prev_key): 26 | for key, value in nested.items(): 27 | if isinstance(value, dict): 28 | mask_fixture_values(value, key) 29 | else: 30 | if key in ('tenantName', 'username'): 31 | nested[key] = 'dummy' 32 | elif prev_key in ('user', 'project', 'tenant') and key == 'name': 33 | nested[key] = 'dummy' 34 | elif prev_key == 'domain' and key == 'id': 35 | nested[key] = 'dummy' 36 | elif key == 'password': 37 | nested[key] = '********' 38 | elif prev_key == 'token' and key in ('expires', 'expires_at'): 39 | nested[key] = '9999-12-31T23:59:59Z' 40 | 41 | 42 | def pre_record_hook(interaction, cassette): 43 | """Hook to mask saved data. 44 | 45 | This hook will be triggered before saving the interaction, and 46 | will perform two tasks: 47 | - mask user, project and password in the saved data 48 | - set token expiration time to an inifinite time. 49 | """ 50 | request_body = interaction.data['request']['body'] 51 | if request_body.get('string'): 52 | parsed_content = json.loads(request_body['string']) 53 | mask_fixture_values(parsed_content, None) 54 | request_body['string'] = json.dumps(parsed_content) 55 | 56 | response_body = interaction.data['response']['body'] 57 | if response_body.get('string'): 58 | parsed_content = json.loads(response_body['string']) 59 | mask_fixture_values(parsed_content, None) 60 | response_body['string'] = json.dumps(parsed_content) 61 | -------------------------------------------------------------------------------- /keystoneauth1/fixture/serializer.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | """A serializer to emit YAML but with request body in nicely formatted JSON.""" 14 | 15 | import json 16 | import os 17 | 18 | import betamax.serializers.base 19 | import yaml 20 | 21 | 22 | def _should_use_block(value): 23 | for c in "\u000a\u000d\u001c\u001d\u001e\u0085\u2028\u2029": 24 | if c in value: 25 | return True 26 | return False 27 | 28 | 29 | def _represent_scalar(self, tag, value, style=None): 30 | if style is None: 31 | if _should_use_block(value): 32 | style = '|' 33 | else: 34 | style = self.default_style 35 | 36 | node = yaml.representer.ScalarNode(tag, value, style=style) 37 | if self.alias_key is not None: 38 | self.represented_objects[self.alias_key] = node 39 | return node 40 | 41 | 42 | def _unicode_representer(dumper, uni): 43 | node = yaml.ScalarNode(tag='tag:yaml.org,2002:str', value=uni) 44 | return node 45 | 46 | 47 | def _indent_json(val): 48 | if not val: 49 | return '' 50 | 51 | return json.dumps( 52 | json.loads(val), 53 | indent=2, 54 | separators=(',', ': '), 55 | sort_keys=False, 56 | default=str, 57 | ) 58 | 59 | 60 | def _is_json_body(interaction): 61 | content_type = interaction['headers'].get('Content-Type', []) 62 | return 'application/json' in content_type 63 | 64 | 65 | class YamlJsonSerializer(betamax.serializers.base.BaseSerializer): 66 | name = "yamljson" 67 | 68 | @staticmethod 69 | def generate_cassette_name(cassette_library_dir, cassette_name): 70 | return os.path.join(cassette_library_dir, f"{cassette_name}.yaml") 71 | 72 | def serialize(self, cassette_data): 73 | # Reserialize internal json with indentation 74 | for interaction in cassette_data['http_interactions']: 75 | for key in ('request', 'response'): 76 | if _is_json_body(interaction[key]): 77 | interaction[key]['body']['string'] = _indent_json( 78 | interaction[key]['body']['string'] 79 | ) 80 | 81 | class MyDumper(yaml.Dumper): 82 | """Specialized Dumper which does nice blocks and unicode.""" 83 | 84 | yaml.representer.BaseRepresenter.represent_scalar = _represent_scalar # type: ignore[method-assign] 85 | 86 | MyDumper.add_representer(str, _unicode_representer) 87 | 88 | return yaml.dump( 89 | cassette_data, Dumper=MyDumper, default_flow_style=False 90 | ) 91 | 92 | def deserialize(self, cassette_data): 93 | try: 94 | deserialized = yaml.safe_load(cassette_data) 95 | except yaml.error.YAMLError: 96 | deserialized = None 97 | 98 | if deserialized is not None: 99 | return deserialized 100 | return {} 101 | -------------------------------------------------------------------------------- /keystoneauth1/hacking/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/hacking/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/hacking/checks.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | """keystoneauth1's pep8 extensions. 14 | 15 | In order to make the review process faster and easier for core devs we are 16 | adding some keystoneauth1 specific pep8 checks. This will catch common 17 | errors so that core devs don't have to. 18 | 19 | """ 20 | 21 | import re 22 | 23 | from hacking import core 24 | 25 | 26 | @core.flake8ext 27 | def check_oslo_namespace_imports(logical_line, blank_before, filename): 28 | oslo_namespace_imports = re.compile( 29 | r"(((from)|(import))\s+oslo\.)|(from\s+oslo\s+import\s+)" 30 | ) 31 | 32 | if re.match(oslo_namespace_imports, logical_line): 33 | msg = ("K333: '{}' must be used instead of '{}'.").format( 34 | logical_line.replace('oslo.', 'oslo_'), logical_line 35 | ) 36 | yield (0, msg) 37 | -------------------------------------------------------------------------------- /keystoneauth1/http_basic.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import base64 14 | import typing as ty 15 | 16 | from keystoneauth1 import plugin 17 | 18 | if ty.TYPE_CHECKING: 19 | from keystoneauth1 import session as ks_session 20 | 21 | AUTH_HEADER_NAME = 'Authorization' 22 | 23 | 24 | class HTTPBasicAuth(plugin.FixedEndpointPlugin): 25 | """A provider that will always use HTTP Basic authentication. 26 | 27 | This is useful to unify session/adapter loading for services 28 | that might be deployed in standalone mode. 29 | """ 30 | 31 | def __init__( 32 | self, 33 | endpoint: str | None = None, 34 | username: str | None = None, 35 | password: str | None = None, 36 | ): 37 | super().__init__(endpoint) 38 | self.username = username 39 | self.password = password 40 | 41 | def get_token(self, session: 'ks_session.Session') -> str | None: 42 | if self.username is None or self.password is None: 43 | return None 44 | token = bytes(f'{self.username}:{self.password}', encoding='utf-8') 45 | encoded = base64.b64encode(token) 46 | return str(encoded, encoding='utf-8') 47 | 48 | def get_headers( 49 | self, session: 'ks_session.Session' 50 | ) -> dict[str, str] | None: 51 | token = self.get_token(session) 52 | if not token: 53 | return None 54 | auth = f'Basic {token}' 55 | return {AUTH_HEADER_NAME: auth} 56 | -------------------------------------------------------------------------------- /keystoneauth1/identity/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.identity import base 14 | from keystoneauth1.identity import generic 15 | from keystoneauth1.identity import v2 16 | from keystoneauth1.identity import v3 17 | from keystoneauth1.identity.v3 import oidc 18 | 19 | 20 | BaseIdentityPlugin = base.BaseIdentityPlugin 21 | 22 | V2Password = v2.Password 23 | """See :class:`keystoneauth1.identity.v2.Password`""" 24 | 25 | V2Token = v2.Token 26 | """See :class:`keystoneauth1.identity.v2.Token`""" 27 | 28 | V3Password = v3.Password 29 | """See :class:`keystoneauth1.identity.v3.Password`""" 30 | 31 | V3Token = v3.Token 32 | """See :class:`keystoneauth1.identity.v3.Token`""" 33 | 34 | Password = generic.Password 35 | """See :class:`keystoneauth1.identity.generic.Password`""" 36 | 37 | Token = generic.Token 38 | """See :class:`keystoneauth1.identity.generic.Token`""" 39 | 40 | V3OidcClientCredentials = oidc.OidcClientCredentials 41 | """See :class:`keystoneauth1.identity.v3.oidc.OidcClientCredentials`""" 42 | 43 | V3OidcPassword = oidc.OidcPassword 44 | """See :class:`keystoneauth1.identity.v3.oidc.OidcPassword`""" 45 | 46 | V3OidcAuthorizationCode = oidc.OidcAuthorizationCode 47 | """See :class:`keystoneauth1.identity.v3.oidc.OidcAuthorizationCode`""" 48 | 49 | V3OidcAccessToken = oidc.OidcAccessToken 50 | """See :class:`keystoneauth1.identity.v3.oidc.OidcAccessToken`""" 51 | 52 | V3OidcDeviceAuthorization = oidc.OidcDeviceAuthorization 53 | """See :class:`keystoneauth1.identity.v3.oidc.OidcDeviceAuthorization`""" 54 | 55 | V3TOTP = v3.TOTP 56 | """See :class:`keystoneauth1.identity.v3.TOTP`""" 57 | 58 | V3TokenlessAuth = v3.TokenlessAuth 59 | """See :class:`keystoneauth1.identity.v3.TokenlessAuth`""" 60 | 61 | V3ApplicationCredential = v3.ApplicationCredential 62 | """See :class:`keystoneauth1.identity.v3.ApplicationCredential`""" 63 | 64 | V3MultiFactor = v3.MultiFactor 65 | """See :class:`keystoneauth1.identity.v3.MultiFactor`""" 66 | 67 | V3OAuth2ClientCredential = v3.OAuth2ClientCredential 68 | """See :class:`keystoneauth1.identity.v3.OAuth2ClientCredential`""" 69 | 70 | V3OAuth2mTlsClientCredential = v3.OAuth2mTlsClientCredential 71 | """See :class:`keystoneauth1.identity.v3.OAuth2mTlsClientCredential`""" 72 | 73 | __all__ = ( 74 | 'BaseIdentityPlugin', 75 | 'Password', 76 | 'Token', 77 | 'V2Password', 78 | 'V2Token', 79 | 'V3Password', 80 | 'V3Token', 81 | 'V3OidcPassword', 82 | 'V3OidcAuthorizationCode', 83 | 'V3OidcAccessToken', 84 | 'V3OidcDeviceAuthorization', 85 | 'V3TOTP', 86 | 'V3TokenlessAuth', 87 | 'V3ApplicationCredential', 88 | 'V3MultiFactor', 89 | 'V3OAuth2ClientCredential', 90 | 'V3OAuth2mTlsClientCredential', 91 | ) 92 | -------------------------------------------------------------------------------- /keystoneauth1/identity/access.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1 import access 15 | from keystoneauth1.identity import base 16 | from keystoneauth1 import session as ks_session 17 | 18 | 19 | class AccessInfoPlugin(base.BaseIdentityPlugin): 20 | """A plugin that turns an existing AccessInfo object into a usable plugin. 21 | 22 | There are cases where reuse of an auth_ref or AccessInfo object is 23 | warranted such as from a cache, from auth_token middleware, or another 24 | source. 25 | 26 | Turn the existing access info object into an identity plugin. This plugin 27 | cannot be refreshed as the AccessInfo object does not contain any 28 | authorizing information. 29 | 30 | :param auth_ref: the existing AccessInfo object. 31 | :type auth_ref: keystoneauth1.access.AccessInfo 32 | :param auth_url: the url where this AccessInfo was retrieved from. Required 33 | if using the AUTH_INTERFACE with get_endpoint. (optional) 34 | """ 35 | 36 | auth_ref: access.AccessInfo 37 | 38 | def __init__( 39 | self, auth_ref: access.AccessInfo, auth_url: str | None = None 40 | ): 41 | super().__init__(auth_url=auth_url, reauthenticate=False) 42 | self.auth_ref = auth_ref 43 | 44 | def get_auth_ref(self, session: ks_session.Session) -> access.AccessInfo: 45 | return self.auth_ref 46 | 47 | def invalidate(self) -> bool: 48 | # NOTE(jamielennox): Don't allow the default invalidation to occur 49 | # because on next authentication request we will only get the same 50 | # auth_ref object again. 51 | return False 52 | -------------------------------------------------------------------------------- /keystoneauth1/identity/generic/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.identity.generic.base import BaseGenericPlugin # noqa 14 | from keystoneauth1.identity.generic.password import Password # noqa 15 | from keystoneauth1.identity.generic.token import Token # noqa 16 | 17 | 18 | __all__ = ('BaseGenericPlugin', 'Password', 'Token') 19 | -------------------------------------------------------------------------------- /keystoneauth1/identity/v3/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | # flake8: noqa: F405 14 | 15 | from keystoneauth1.identity.v3.application_credential import * # noqa 16 | from keystoneauth1.identity.v3.base import * # noqa 17 | from keystoneauth1.identity.v3.federation import * # noqa 18 | from keystoneauth1.identity.v3.k2k import * # noqa 19 | from keystoneauth1.identity.v3.multi_factor import * # noqa 20 | from keystoneauth1.identity.v3.oidc import * # noqa 21 | from keystoneauth1.identity.v3.password import * # noqa 22 | from keystoneauth1.identity.v3.receipt import * # noqa 23 | from keystoneauth1.identity.v3.token import * # noqa 24 | from keystoneauth1.identity.v3.totp import * # noqa 25 | from keystoneauth1.identity.v3.tokenless_auth import * # noqa 26 | from keystoneauth1.identity.v3.oauth2_client_credential import * # noqa 27 | from keystoneauth1.identity.v3.oauth2_mtls_client_credential import * # noqa 28 | 29 | 30 | __all__ = ( 31 | 'ApplicationCredential', 32 | 'ApplicationCredentialMethod', 33 | 'Auth', 34 | 'AuthConstructor', 35 | 'AuthMethod', 36 | 'BaseAuth', 37 | 'FederationBaseAuth', 38 | 'Keystone2Keystone', 39 | 'Password', 40 | 'PasswordMethod', 41 | 'Token', 42 | 'TokenMethod', 43 | 'OidcAccessToken', 44 | 'OidcAuthorizationCode', 45 | 'OidcClientCredentials', 46 | 'OidcPassword', 47 | 'TOTPMethod', 48 | 'TOTP', 49 | 'TokenlessAuth', 50 | 'ReceiptMethod', 51 | 'MultiFactor', 52 | 'OAuth2ClientCredential', 53 | 'OAuth2ClientCredentialMethod', 54 | 'OAuth2mTlsClientCredential', 55 | ) 56 | -------------------------------------------------------------------------------- /keystoneauth1/identity/v3/receipt.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import typing as ty 14 | 15 | from keystoneauth1.identity.v3 import base 16 | from keystoneauth1 import session as ks_session 17 | 18 | 19 | __all__ = ('ReceiptMethod',) 20 | 21 | 22 | class ReceiptMethod(base.AuthMethod): 23 | """Construct an Auth plugin to continue authentication with a receipt. 24 | 25 | :param string receipt: Receipt for authentication. 26 | """ 27 | 28 | receipt: str 29 | 30 | def __init__(self, *, receipt: str) -> None: 31 | self.receipt = receipt 32 | 33 | def get_auth_data( 34 | self, 35 | session: ks_session.Session, 36 | auth: base.Auth, 37 | headers: dict[str, str], 38 | request_kwargs: dict[str, object], 39 | ) -> tuple[None, None] | tuple[str, ty.Mapping[str, object]]: 40 | """Add the auth receipt to the headers. 41 | 42 | We explicitly return None to avoid being added to the request 43 | methods, or body. 44 | """ 45 | headers['Openstack-Auth-Receipt'] = self.receipt 46 | return (None, None) 47 | 48 | def get_cache_id_elements(self) -> dict[str, str | None]: 49 | return {'receipt_receipt': self.receipt} 50 | -------------------------------------------------------------------------------- /keystoneauth1/identity/v3/token.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import typing as ty 14 | 15 | from keystoneauth1.identity.v3 import base 16 | from keystoneauth1 import session as ks_session 17 | 18 | 19 | __all__ = ('TokenMethod', 'Token') 20 | 21 | 22 | class TokenMethod(base.AuthMethod): 23 | """Construct an Auth plugin to fetch a token from a token. 24 | 25 | :param string token: Token for authentication. 26 | """ 27 | 28 | token: str 29 | 30 | def __init__(self, *, token: str) -> None: 31 | self.token = token 32 | 33 | def get_auth_data( 34 | self, 35 | session: ks_session.Session, 36 | auth: base.Auth, 37 | headers: dict[str, str], 38 | request_kwargs: dict[str, object], 39 | ) -> tuple[None, None] | tuple[str, ty.Mapping[str, object]]: 40 | headers['X-Auth-Token'] = self.token 41 | return 'token', {'id': self.token} 42 | 43 | def get_cache_id_elements(self) -> dict[str, str | None]: 44 | return {'token_token': self.token} 45 | 46 | 47 | class Token(base.Auth): 48 | """A plugin for authenticating with an existing Token. 49 | 50 | :param string auth_url: Identity service endpoint for authentication. 51 | :param string token: Token for authentication. 52 | :param string trust_id: Trust ID for trust scoping. 53 | :param string domain_id: Domain ID for domain scoping. 54 | :param string domain_name: Domain name for domain scoping. 55 | :param string project_id: Project ID for project scoping. 56 | :param string project_name: Project name for project scoping. 57 | :param string project_domain_id: Project's domain ID for project. 58 | :param string project_domain_name: Project's domain name for project. 59 | :param bool reauthenticate: Allow fetching a new token if the current one 60 | is going to expire. (optional) default True 61 | """ 62 | 63 | _auth_method_class = TokenMethod 64 | 65 | def __init__( 66 | self, 67 | auth_url: str, 68 | token: str, 69 | *, 70 | unscoped: bool = False, 71 | trust_id: str | None = None, 72 | system_scope: str | None = None, 73 | domain_id: str | None = None, 74 | domain_name: str | None = None, 75 | project_id: str | None = None, 76 | project_name: str | None = None, 77 | project_domain_id: str | None = None, 78 | project_domain_name: str | None = None, 79 | reauthenticate: bool = True, 80 | include_catalog: bool = True, 81 | ) -> None: 82 | method = self._auth_method_class(token=token) 83 | super().__init__( 84 | auth_url, 85 | [method], 86 | unscoped=unscoped, 87 | trust_id=trust_id, 88 | system_scope=system_scope, 89 | domain_id=domain_id, 90 | domain_name=domain_name, 91 | project_id=project_id, 92 | project_name=project_name, 93 | project_domain_id=project_domain_id, 94 | project_domain_name=project_domain_name, 95 | reauthenticate=reauthenticate, 96 | include_catalog=include_catalog, 97 | ) 98 | -------------------------------------------------------------------------------- /keystoneauth1/loading/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | # flake8: noqa: F405 14 | 15 | from keystoneauth1.loading import adapter 16 | from keystoneauth1.loading.base import * # noqa 17 | from keystoneauth1.loading import cli 18 | from keystoneauth1.loading import conf 19 | from keystoneauth1.loading.identity import * # noqa 20 | from keystoneauth1.loading.opts import * # noqa 21 | from keystoneauth1.loading import session 22 | 23 | 24 | register_auth_argparse_arguments = cli.register_argparse_arguments 25 | load_auth_from_argparse_arguments = cli.load_from_argparse_arguments 26 | 27 | get_auth_common_conf_options = conf.get_common_conf_options 28 | get_auth_plugin_conf_options = conf.get_plugin_conf_options 29 | register_auth_conf_options = conf.register_conf_options 30 | load_auth_from_conf_options = conf.load_from_conf_options 31 | 32 | register_session_argparse_arguments = session.register_argparse_arguments 33 | load_session_from_argparse_arguments = session.load_from_argparse_arguments 34 | register_session_conf_options = session.register_conf_options 35 | load_session_from_conf_options = session.load_from_conf_options 36 | get_session_conf_options = session.get_conf_options 37 | 38 | register_adapter_argparse_arguments = adapter.register_argparse_arguments 39 | register_service_adapter_argparse_arguments = ( 40 | adapter.register_service_argparse_arguments 41 | ) 42 | register_adapter_conf_options = adapter.register_conf_options 43 | load_adapter_from_conf_options = adapter.load_from_conf_options 44 | get_adapter_conf_options = adapter.get_conf_options 45 | 46 | 47 | __all__ = ( 48 | # loading.base 49 | 'BaseLoader', 50 | 'get_available_plugin_names', 51 | 'get_available_plugin_loaders', 52 | 'get_plugin_loader', 53 | 'PLUGIN_NAMESPACE', 54 | # loading.identity 55 | 'BaseIdentityLoader', 56 | 'BaseV2Loader', 57 | 'BaseV3Loader', 58 | 'BaseFederationLoader', 59 | 'BaseGenericLoader', 60 | # auth cli 61 | 'register_auth_argparse_arguments', 62 | 'load_auth_from_argparse_arguments', 63 | # auth conf 64 | 'get_auth_common_conf_options', 65 | 'get_auth_plugin_conf_options', 66 | 'register_auth_conf_options', 67 | 'load_auth_from_conf_options', 68 | # session 69 | 'register_session_argparse_arguments', 70 | 'load_session_from_argparse_arguments', 71 | 'register_session_conf_options', 72 | 'load_session_from_conf_options', 73 | 'get_session_conf_options', 74 | # adapter 75 | 'register_adapter_argparse_arguments', 76 | 'register_service_adapter_argparse_arguments', 77 | 'register_adapter_conf_options', 78 | 'load_adapter_from_conf_options', 79 | 'get_adapter_conf_options', 80 | # loading.opts 81 | 'Opt', 82 | ) 83 | -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/loading/_plugins/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/admin_token.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1 import loading 15 | from keystoneauth1.loading import opts 16 | from keystoneauth1 import token_endpoint 17 | 18 | 19 | class AdminToken(loading.BaseLoader[token_endpoint.Token]): 20 | """Authenticate with an existing token and a known endpoint. 21 | 22 | This plugin is primarily useful for development or for use with identity 23 | service ADMIN tokens. Because this token is used directly there is no 24 | fetching a service catalog or determining scope information and so it 25 | cannot be used by clients that expect use this scope information. 26 | 27 | Because there is no service catalog the endpoint that is supplied with 28 | initialization is used for all operations performed with this plugin so 29 | must be the full base URL to an actual service. 30 | """ 31 | 32 | @property 33 | def plugin_class(self) -> type[token_endpoint.Token]: 34 | return token_endpoint.Token 35 | 36 | def get_options(self) -> list[opts.Opt]: 37 | options = super().get_options() 38 | 39 | options.extend( 40 | [ 41 | loading.Opt( 42 | 'endpoint', 43 | deprecated=[loading.Opt('url')], 44 | help='The endpoint that will always be used', 45 | ), 46 | loading.Opt( 47 | 'token', 48 | secret=True, 49 | help='The token that will always be used', 50 | ), 51 | ] 52 | ) 53 | 54 | return options 55 | -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/http_basic.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1 import http_basic 15 | from keystoneauth1 import loading 16 | from keystoneauth1.loading import opts 17 | 18 | 19 | class HTTPBasicAuth(loading.BaseLoader[http_basic.HTTPBasicAuth]): 20 | """Use HTTP Basic authentication to perform requests. 21 | 22 | This can be used to instantiate clients for services deployed in 23 | standalone mode. 24 | 25 | There is no fetching a service catalog or determining scope information 26 | and so it cannot be used by clients that expect to use this scope 27 | information. 28 | 29 | """ 30 | 31 | @property 32 | def plugin_class(self) -> type[http_basic.HTTPBasicAuth]: 33 | return http_basic.HTTPBasicAuth 34 | 35 | def get_options(self) -> list[opts.Opt]: 36 | options = super().get_options() 37 | 38 | options.extend( 39 | [ 40 | loading.Opt( 41 | 'username', 42 | help='Username', 43 | deprecated=[loading.Opt('user-name')], 44 | ), 45 | loading.Opt( 46 | 'password', 47 | secret=True, 48 | prompt='Password: ', 49 | help="User's password", 50 | ), 51 | loading.Opt( 52 | 'endpoint', help='The endpoint that will always be used' 53 | ), 54 | ] 55 | ) 56 | 57 | return options 58 | -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/identity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/loading/_plugins/identity/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/identity/generic.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1 import identity 15 | from keystoneauth1 import loading 16 | from keystoneauth1.loading import opts 17 | 18 | 19 | class Token(loading.BaseGenericLoader[identity.Token]): 20 | """Given an existing token rescope it to another target. 21 | 22 | Use the Identity service's rescope mechanism to get a new token based upon 23 | an existing token. Because an auth plugin requires a service catalog and 24 | scope information it is often easier to fetch a new token based on an 25 | existing one than validate and reuse the one you already have. 26 | 27 | As a generic plugin this plugin is identity version independent and will 28 | discover available versions before use. This means it expects to be 29 | provided an unversioned URL to operate against. 30 | """ 31 | 32 | @property 33 | def plugin_class(self) -> type[identity.Token]: 34 | return identity.Token 35 | 36 | def get_options(self) -> list[opts.Opt]: 37 | options = super().get_options() 38 | 39 | options.extend( 40 | [ 41 | loading.Opt( 42 | 'token', secret=True, help='Token to authenticate with' 43 | ) 44 | ] 45 | ) 46 | 47 | return options 48 | 49 | 50 | class Password(loading.BaseGenericLoader[identity.Password]): 51 | """Authenticate with a username and password. 52 | 53 | Authenticate to the identity service using the provided username and 54 | password. This is the standard and most common form of authentication. 55 | 56 | As a generic plugin this plugin is identity version independent and will 57 | discover available versions before use. This means it expects to be 58 | provided an unversioned URL to operate against. 59 | """ 60 | 61 | @property 62 | def plugin_class(self) -> type[identity.Password]: 63 | return identity.Password 64 | 65 | def get_options(self) -> list[opts.Opt]: 66 | options = super().get_options() 67 | options.extend( 68 | [ 69 | loading.Opt('user-id', help='User id'), 70 | loading.Opt( 71 | 'username', 72 | help='Username', 73 | deprecated=[loading.Opt('user-name')], 74 | ), 75 | loading.Opt('user-domain-id', help="User's domain id"), 76 | loading.Opt('user-domain-name', help="User's domain name"), 77 | loading.Opt( 78 | 'password', 79 | secret=True, 80 | prompt='Password: ', 81 | help="User's password", 82 | ), 83 | ] 84 | ) 85 | return options 86 | -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/identity/v2.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1 import identity 15 | from keystoneauth1 import loading 16 | from keystoneauth1.loading import opts 17 | 18 | 19 | class Token(loading.BaseV2Loader[identity.V2Token]): 20 | """Given an existing token rescope it to another target. 21 | 22 | Use the Identity service's rescope mechanism to get a new token based upon 23 | an existing token. Because an auth plugin requires a service catalog and 24 | scope information it is often easier to fetch a new token based on an 25 | existing one than validate and reuse the one you already have. 26 | """ 27 | 28 | @property 29 | def plugin_class(self) -> type[identity.V2Token]: 30 | return identity.V2Token 31 | 32 | def get_options(self) -> list[opts.Opt]: 33 | options = super().get_options() 34 | 35 | options.extend([loading.Opt('token', secret=True, help='Token')]) 36 | 37 | return options 38 | 39 | 40 | class Password(loading.BaseV2Loader[identity.V2Password]): 41 | """Authenticate with a username and password. 42 | 43 | Authenticate to the identity service using the provided username and 44 | password. This is the standard and most common form of authentication. 45 | """ 46 | 47 | @property 48 | def plugin_class(self) -> type[identity.V2Password]: 49 | return identity.V2Password 50 | 51 | def get_options(self) -> list[opts.Opt]: 52 | options = super().get_options() 53 | 54 | options.extend( 55 | [ 56 | loading.Opt( 57 | 'username', 58 | deprecated=[loading.Opt('user-name')], 59 | help='Username to login with', 60 | ), 61 | loading.Opt('user-id', help='User ID to login with'), 62 | loading.Opt( 63 | 'password', 64 | secret=True, 65 | prompt='Password: ', 66 | help='Password to use', 67 | ), 68 | ] 69 | ) 70 | 71 | return options 72 | -------------------------------------------------------------------------------- /keystoneauth1/loading/_plugins/noauth.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from keystoneauth1 import loading 15 | from keystoneauth1.loading import opts 16 | from keystoneauth1 import noauth 17 | 18 | 19 | class NoAuth(loading.BaseLoader[noauth.NoAuth]): 20 | """Use no tokens to perform requests. 21 | 22 | This can be used to instantiate clients for services deployed in 23 | noauth/standalone mode. 24 | 25 | There is no fetching a service catalog or determining scope information 26 | and so it cannot be used by clients that expect to use this scope 27 | information. 28 | 29 | """ 30 | 31 | @property 32 | def plugin_class(self) -> type[noauth.NoAuth]: 33 | return noauth.NoAuth 34 | 35 | def get_options(self) -> list[opts.Opt]: 36 | options = super().get_options() 37 | 38 | options.extend( 39 | [ 40 | loading.Opt( 41 | 'endpoint', help='The endpoint that will always be used' 42 | ) 43 | ] 44 | ) 45 | 46 | return options 47 | -------------------------------------------------------------------------------- /keystoneauth1/loading/_utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import typing as ty 14 | 15 | if ty.TYPE_CHECKING: 16 | from oslo_config import cfg as _cfg 17 | 18 | cfg = None 19 | _NOT_FOUND = object() 20 | 21 | 22 | def get_oslo_config() -> '_cfg': 23 | """Runtime load the oslo.config object. 24 | 25 | In performance optimization of openstackclient it was determined that even 26 | optimistically loading oslo.config if available had a performance cost. 27 | Given that we used to only raise the ImportError when the function was 28 | called also attempt to do the import to do everything at runtime. 29 | """ 30 | global cfg 31 | 32 | # First Call 33 | if not cfg: 34 | try: 35 | from oslo_config import cfg 36 | except ImportError: 37 | cfg = _NOT_FOUND 38 | 39 | if cfg is _NOT_FOUND: 40 | raise ImportError( 41 | "oslo.config is not an automatic dependency of " 42 | "keystoneauth. If you wish to use oslo.config " 43 | "you need to import it into your application's " 44 | "requirements file. " 45 | ) 46 | 47 | return cfg 48 | -------------------------------------------------------------------------------- /keystoneauth1/noauth.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import typing as ty 14 | 15 | from keystoneauth1 import plugin 16 | 17 | if ty.TYPE_CHECKING: 18 | from keystoneauth1 import session as ks_session 19 | 20 | 21 | class NoAuth(plugin.FixedEndpointPlugin): 22 | """A provider that will always use no auth. 23 | 24 | This is useful to unify session/adapter loading for services 25 | that might be deployed in standalone/noauth mode. 26 | """ 27 | 28 | def get_token(self, session: 'ks_session.Session') -> str | None: 29 | return 'notused' 30 | -------------------------------------------------------------------------------- /keystoneauth1/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/py.typed -------------------------------------------------------------------------------- /keystoneauth1/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/access/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/access/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/README: -------------------------------------------------------------------------------- 1 | This directory holds the betamax test cassettes that are pre-generated 2 | for unit testing. This can be removed in the future with a functional 3 | test that stands up a full devstack, records a cassette and then 4 | replays it as part of the test suite. 5 | 6 | Until the functional testing is implemented do not remove this 7 | directory or enclosed files. 8 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/keystone_v2_sample_request.json: -------------------------------------------------------------------------------- 1 | {"auth":{"tenantName": "customer-x", "passwordCredentials": {"username": "joeuser", "password": "secrete"}}} 2 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/keystone_v2_sample_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "access":{ 3 | "token":{ 4 | "expires":"2012-02-05T00:00:00", 5 | "id":"887665443383838", 6 | "tenant":{ 7 | "id":"1", 8 | "name":"customer-x" 9 | } 10 | }, 11 | "serviceCatalog":[ 12 | { 13 | "endpoints":[ 14 | { 15 | "adminURL":"http://swift.admin-nets.local:8080/", 16 | "region":"RegionOne", 17 | "internalURL":"http://127.0.0.1:8080/v1/AUTH_1", 18 | "publicURL":"http://swift.publicinternets.com/v1/AUTH_1" 19 | } 20 | ], 21 | "type":"object-store", 22 | "name":"swift" 23 | }, 24 | { 25 | "endpoints":[ 26 | { 27 | "adminURL":"http://cdn.admin-nets.local/v1.1/1", 28 | "region":"RegionOne", 29 | "internalURL":"http://127.0.0.1:7777/v1.1/1", 30 | "publicURL":"http://cdn.publicinternets.com/v1.1/1" 31 | } 32 | ], 33 | "type":"object-store", 34 | "name":"cdn" 35 | } 36 | ], 37 | "user":{ 38 | "id":"1", 39 | "roles":[ 40 | { 41 | "tenantId":"1", 42 | "id":"3", 43 | "name":"Member" 44 | } 45 | ], 46 | "name":"joeuser" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/keystone_v3_sample_request.json: -------------------------------------------------------------------------------- 1 | { "auth": { 2 | "identity": { 3 | "methods": ["password"], 4 | "password": { 5 | "user": { 6 | "name": "admin", 7 | "domain": { "id": "default" }, 8 | "password": "adminpwd" 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/keystone_v3_sample_response.json: -------------------------------------------------------------------------------- 1 | {"token": {"methods": ["password"], "roles": [{"id": 2 | "9fe2ff9ee4384b1894a90878d3e92bab", "name": "_member_"}, {"id": 3 | "c703057be878458588961ce9a0ce686b", "name": "admin"}], "expires_at": 4 | "2014-06-10T2:55:16.806001Z", "project": {"domain": {"id": "default", "name": 5 | "Default"}, "id": "8538a3f13f9541b28c2620eb19065e45", "name": "admin"}, 6 | "catalog": [{"endpoints": [{"url": "http://localhost:3537/v2.0", "region": 7 | "RegionOne", "interface": "admin", "id": "29beb2f1567642eb810b042b6719ea88"}, 8 | {"url": "http://localhost:5000/v2.0", "region": "RegionOne", "interface": 9 | "internal", "id": "8707e3735d4415c97ae231b4841eb1c"}, {"url": 10 | "http://localhost:5000/v2.0", "region": "RegionOne", "interface": "public", 11 | "id": "ef303187fc8d41668f25199c298396a5"}], "type": "identity", "id": 12 | "bd73972c0e14fb69bae8ff76e112a90", "name": "keystone"}], "extras": {}, 13 | "user": {"domain": {"id": "default", "name": "Default"}, "id": 14 | "3ec3164f750146be97f21559ee4d9c51", "name": "admin"}, "audit_ids": 15 | ["yRt0UrxJSs6-WYJgwEMMmg"], "issued_at": "201406-10T20:55:16.806027Z"}} 16 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/ksa_betamax_test_cassette.yaml: -------------------------------------------------------------------------------- 1 | http_interactions: 2 | - request: 3 | body: 4 | string: |- 5 | { 6 | "auth": { 7 | "tenantName": "test_tenant_name", 8 | "passwordCredentials": { 9 | "username": "test_user_name", 10 | "password": "test_password" 11 | } 12 | } 13 | } 14 | encoding: utf-8 15 | headers: 16 | Content-Length: 17 | - '128' 18 | Accept-Encoding: 19 | - gzip, deflate 20 | Accept: 21 | - application/json 22 | User-Agent: 23 | - keystoneauth1 24 | Connection: 25 | - keep-alive 26 | Content-Type: 27 | - application/json 28 | method: POST 29 | uri: http://keystoneauth-betamax.test/v2.0/tokens 30 | response: 31 | body: 32 | string: |- 33 | { 34 | "access": { 35 | "token": { 36 | "issued_at": "2015-11-27T15:17:19.755470", 37 | "expires": "2015-11-27T16:17:19Z", 38 | "id": "c000c5ee4ba04594a00886028584b50d", 39 | "tenant": { 40 | "enabled": true, 41 | "description": null, 42 | "name": "test_tenant_name", 43 | "id": "6932cad596634a61ac9c759fb91beef1" 44 | }, 45 | "audit_ids": [ 46 | "jY3gYg_YTbmzY2a4ioGuCw" 47 | ] 48 | }, 49 | "user": { 50 | "username": "test_user_name", 51 | "roles_links": [], 52 | "id": "96995e6cc15b40fa8e7cd762f6a5d4c0", 53 | "roles": [ 54 | { 55 | "name": "_member_" 56 | } 57 | ], 58 | "name": "67eff5f6-9477-4961-88b4-437e6596a795" 59 | }, 60 | "metadata": { 61 | "is_admin": 0, 62 | "roles": [ 63 | "9fe2ff9ee4384b1894a90878d3e92bab" 64 | ] 65 | } 66 | } 67 | } 68 | encoding: null 69 | headers: 70 | X-Openstack-Request-Id: 71 | - req-f9e188b4-06fd-4a4c-a952-2315b368218c 72 | Content-Length: 73 | - '2684' 74 | Connection: 75 | - keep-alive 76 | Date: 77 | - Fri, 27 Nov 2015 15:17:19 GMT 78 | Content-Type: 79 | - application/json 80 | Vary: 81 | - X-Auth-Token 82 | X-Distribution: 83 | - Ubuntu 84 | Server: 85 | - Fake 86 | status: 87 | message: OK 88 | code: 200 89 | url: http://keystoneauth-betamax.test/v2.0/tokens 90 | recorded_at: '2015-11-27T15:17:19' 91 | recorded_with: betamax/0.5.1 92 | 93 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/ksa_serializer_data.json: -------------------------------------------------------------------------------- 1 | {"http_interactions": [{"request": {"body": {"string": "{\"auth\": {\"tenantName\": \"test_tenant_name\", \"passwordCredentials\": {\"username\": \"test_user_name\", \"password\": \"test_password\"}}}", "encoding": "utf-8"}, "headers": {"Content-Length": ["128"], "Accept-Encoding": ["gzip, deflate"], "Accept": ["application/json"], "User-Agent": ["keystoneauth1"], "Connection": ["keep-alive"], "Content-Type": ["application/json"]}, "method": "POST", "uri": "http://keystoneauth-betamax.test/v2.0/tokens"}, "response": {"body": {"string": "{\"access\": {\"token\": {\"issued_at\": \"2015-11-27T15:17:19.755470\", \"expires\": \"2015-11-27T16:17:19Z\", \"id\": \"c000c5ee4ba04594a00886028584b50d\", \"tenant\": {\"description\": null, \"enabled\": true, \"id\": \"6932cad596634a61ac9c759fb91beef1\", \"name\": \"test_tenant_name\"}, \"audit_ids\": [\"jY3gYg_YTbmzY2a4ioGuCw\"]}, \"user\": {\"username\": \"test_user_name\", \"roles_links\": [], \"id\": \"96995e6cc15b40fa8e7cd762f6a5d4c0\", \"roles\": [{\"name\": \"_member_\"}], \"name\": \"67eff5f6-9477-4961-88b4-437e6596a795\"}, \"metadata\": {\"is_admin\": 0, \"roles\": [\"9fe2ff9ee4384b1894a90878d3e92bab\"]}}}", "encoding": null}, "headers": {"X-Openstack-Request-Id": ["req-f9e188b4-06fd-4a4c-a952-2315b368218c"], "Content-Length": ["2684"], "Connection": ["keep-alive"], "Date": ["Fri, 27 Nov 2015 15:17:19 GMT"], "Content-Type": ["application/json"], "Vary": ["X-Auth-Token"], "X-Distribution": ["Ubuntu"], "Server": ["Fake"]}, "status": {"message": "OK", "code": 200}, "url": "http://keystoneauth-betamax.test/v2.0/tokens"}, "recorded_at": "2015-11-27T15:17:19"}], "recorded_with": "betamax/0.5.1"} 2 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/data/test_pre_record_hook.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/data/test_pre_record_hook.json -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/exceptions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/exceptions/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/exceptions/test_exceptions.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1 import exceptions 14 | from keystoneauth1.tests.unit import utils 15 | 16 | 17 | class ExceptionTests(utils.TestCase): 18 | def test_clientexception_with_message(self): 19 | test_message = 'Unittest exception message.' 20 | exc = exceptions.ClientException(message=test_message) 21 | self.assertEqual(test_message, exc.message) 22 | 23 | def test_clientexception_with_no_message(self): 24 | exc = exceptions.ClientException() 25 | self.assertEqual(exceptions.ClientException.__name__, exc.message) 26 | 27 | def test_using_default_message(self): 28 | exc = exceptions.AuthorizationFailure() 29 | self.assertEqual(exceptions.AuthorizationFailure.message, exc.message) 30 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/extras/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/kerberos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/extras/kerberos/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/kerberos/base.py: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2011 OpenStack Foundation 2 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from keystoneauth1.tests.unit.extras.kerberos import utils 17 | from keystoneauth1.tests.unit import utils as test_utils 18 | 19 | 20 | REQUEST = {'auth': {'identity': {'methods': ['kerberos'], 'kerberos': {}}}} 21 | 22 | 23 | class TestCase(test_utils.TestCase): 24 | """Test case base class for Kerberos unit tests.""" 25 | 26 | TEST_V3_URL = test_utils.TestCase.TEST_ROOT_URL + 'v3' 27 | 28 | def setUp(self): 29 | super().setUp() 30 | 31 | km = utils.KerberosMock(self.requests_mock) 32 | self.kerberos_mock = self.useFixture(km) 33 | 34 | def assertRequestBody(self, body=None): 35 | """Ensure the request body is the standard Kerberos auth request. 36 | 37 | :param dict body: the body to compare. If not provided the last request 38 | body will be used. 39 | """ 40 | if not body: 41 | body = self.requests_mock.last_request.json() 42 | 43 | self.assertEqual(REQUEST, body) 44 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/kerberos/test_fedkerb_loading.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1 import exceptions 14 | from keystoneauth1 import loading 15 | from keystoneauth1.tests.unit import utils as test_utils 16 | 17 | 18 | class FedKerbLoadingTests(test_utils.TestCase): 19 | def test_options(self): 20 | opts = [ 21 | o.name 22 | for o in loading.get_plugin_loader('v3fedkerb').get_options() 23 | ] 24 | 25 | allowed_opts = [ 26 | 'system-scope', 27 | 'domain-id', 28 | 'domain-name', 29 | 'identity-provider', 30 | 'project-id', 31 | 'project-name', 32 | 'project-domain-id', 33 | 'project-domain-name', 34 | 'protocol', 35 | 'trust-id', 36 | 'auth-url', 37 | 'mutual-auth', 38 | ] 39 | 40 | self.assertCountEqual(allowed_opts, opts) 41 | 42 | def create(self, **kwargs): 43 | loader = loading.get_plugin_loader('v3fedkerb') 44 | return loader.load_from_options(**kwargs) 45 | 46 | def test_load_none(self): 47 | self.assertRaises(exceptions.MissingRequiredOptions, self.create) 48 | 49 | def test_load(self): 50 | self.create( 51 | auth_url='auth_url', identity_provider='idp', protocol='protocol' 52 | ) 53 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/kerberos/test_kerberos_loading.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1 import loading 14 | from keystoneauth1.tests.unit import utils as test_utils 15 | 16 | 17 | class KerberosLoadingTests(test_utils.TestCase): 18 | def test_options(self): 19 | opts = [ 20 | o.name 21 | for o in loading.get_plugin_loader('v3kerberos').get_options() 22 | ] 23 | 24 | allowed_opts = [ 25 | 'system-scope', 26 | 'domain-id', 27 | 'domain-name', 28 | 'project-id', 29 | 'project-name', 30 | 'project-domain-id', 31 | 'project-domain-name', 32 | 'trust-id', 33 | 'auth-url', 34 | 'mutual-auth', 35 | ] 36 | 37 | self.assertCountEqual(allowed_opts, opts) 38 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/kerberos/test_v3.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.extras import kerberos 14 | from keystoneauth1 import session 15 | from keystoneauth1.tests.unit.extras.kerberos import base 16 | 17 | 18 | class TestKerberosAuth(base.TestCase): 19 | def setUp(self): 20 | if kerberos.requests_kerberos is None: 21 | self.skipTest("Kerberos support isn't available.") 22 | 23 | super().setUp() 24 | 25 | def test_authenticate_with_kerberos_domain_scoped(self): 26 | token_id, token_body = self.kerberos_mock.mock_auth_success() 27 | 28 | a = kerberos.Kerberos(self.TEST_ROOT_URL + 'v3') 29 | s = session.Session(a) 30 | token = a.get_token(s) 31 | 32 | self.assertRequestBody() 33 | self.assertEqual( 34 | self.kerberos_mock.challenge_header, 35 | self.requests_mock.last_request.headers['Authorization'], 36 | ) 37 | self.assertEqual(token_id, a.auth_ref.auth_token) 38 | self.assertEqual(token_id, token) 39 | 40 | def test_authenticate_with_kerberos_mutual_authentication_required(self): 41 | token_id, token_body = self.kerberos_mock.mock_auth_success() 42 | 43 | a = kerberos.Kerberos( 44 | self.TEST_ROOT_URL + 'v3', mutual_auth='required' 45 | ) 46 | s = session.Session(a) 47 | token = a.get_token(s) 48 | 49 | self.assertRequestBody() 50 | self.assertEqual( 51 | self.kerberos_mock.challenge_header, 52 | self.requests_mock.last_request.headers['Authorization'], 53 | ) 54 | self.assertEqual(token_id, a.auth_ref.auth_token) 55 | self.assertEqual(token_id, token) 56 | self.assertEqual(self.kerberos_mock.called_auth_server, True) 57 | 58 | def test_authenticate_with_kerberos_mutual_authentication_disabled(self): 59 | token_id, token_body = self.kerberos_mock.mock_auth_success() 60 | 61 | a = kerberos.Kerberos( 62 | self.TEST_ROOT_URL + 'v3', mutual_auth='disabled' 63 | ) 64 | s = session.Session(a) 65 | token = a.get_token(s) 66 | 67 | self.assertRequestBody() 68 | self.assertEqual( 69 | self.kerberos_mock.challenge_header, 70 | self.requests_mock.last_request.headers['Authorization'], 71 | ) 72 | self.assertEqual(token_id, a.auth_ref.auth_token) 73 | self.assertEqual(token_id, token) 74 | self.assertEqual(self.kerberos_mock.called_auth_server, False) 75 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/kerberos/utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import uuid 14 | 15 | import fixtures 16 | 17 | try: 18 | # requests_kerberos won't be available on py3, it doesn't work with py3. 19 | import requests_kerberos 20 | except ImportError: 21 | requests_kerberos = None 22 | 23 | from keystoneauth1 import fixture as ks_fixture 24 | from keystoneauth1.tests.unit import utils as test_utils 25 | 26 | 27 | class KerberosMock(fixtures.Fixture): 28 | def __init__(self, requests_mock): 29 | super().__init__() 30 | 31 | self.challenge_header = f'Negotiate {uuid.uuid4().hex}' 32 | self.pass_header = f'Negotiate {uuid.uuid4().hex}' 33 | self.requests_mock = requests_mock 34 | 35 | def setUp(self): 36 | super().setUp() 37 | 38 | if requests_kerberos is None: 39 | return 40 | 41 | m = fixtures.MockPatchObject( 42 | requests_kerberos.HTTPKerberosAuth, 43 | 'generate_request_header', 44 | self._generate_request_header, 45 | ) 46 | 47 | self.header_fixture = self.useFixture(m) 48 | 49 | m = fixtures.MockPatchObject( 50 | requests_kerberos.HTTPKerberosAuth, 51 | 'authenticate_server', 52 | self._authenticate_server, 53 | ) 54 | 55 | self.authenticate_fixture = self.useFixture(m) 56 | 57 | def _generate_request_header(self, *args, **kwargs): 58 | return self.challenge_header 59 | 60 | def _authenticate_server(self, response): 61 | self.called_auth_server = True 62 | return response.headers.get('www-authenticate') == self.pass_header 63 | 64 | def mock_auth_success( 65 | self, 66 | token_id=None, 67 | token_body=None, 68 | method='POST', 69 | url=test_utils.TestCase.TEST_ROOT_URL + 'v3/auth/tokens', 70 | ): 71 | if not token_id: 72 | token_id = uuid.uuid4().hex 73 | if not token_body: 74 | token_body = ks_fixture.V3Token() 75 | 76 | self.called_auth_server = False 77 | 78 | response_list = [ 79 | { 80 | 'text': 'Fail', 81 | 'status_code': 401, 82 | 'headers': {'WWW-Authenticate': 'Negotiate'}, 83 | }, 84 | { 85 | 'headers': { 86 | 'X-Subject-Token': token_id, 87 | 'Content-Type': 'application/json', 88 | 'WWW-Authenticate': self.pass_header, 89 | }, 90 | 'status_code': 200, 91 | 'json': token_body, 92 | }, 93 | ] 94 | 95 | self.requests_mock.register_uri( 96 | method, url, response_list=response_list 97 | ) 98 | 99 | return token_id, token_body 100 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/oauth1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/extras/oauth1/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/oauth1/test_oauth1_loading.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import uuid 14 | 15 | from keystoneauth1 import loading 16 | from keystoneauth1.tests.unit import utils as test_utils 17 | 18 | 19 | class OAuth1LoadingTests(test_utils.TestCase): 20 | def setUp(self): 21 | super().setUp() 22 | self.auth_url = uuid.uuid4().hex 23 | 24 | def create(self, **kwargs): 25 | kwargs.setdefault('auth_url', self.auth_url) 26 | loader = loading.get_plugin_loader('v3oauth1') 27 | return loader.load_from_options(**kwargs) 28 | 29 | def test_basic(self): 30 | access_key = uuid.uuid4().hex 31 | access_secret = uuid.uuid4().hex 32 | consumer_key = uuid.uuid4().hex 33 | consumer_secret = uuid.uuid4().hex 34 | 35 | p = self.create( 36 | access_key=access_key, 37 | access_secret=access_secret, 38 | consumer_key=consumer_key, 39 | consumer_secret=consumer_secret, 40 | ) 41 | 42 | oauth_method = p.auth_methods[0] 43 | 44 | self.assertEqual(self.auth_url, p.auth_url) 45 | self.assertEqual(access_key, oauth_method.access_key) 46 | self.assertEqual(access_secret, oauth_method.access_secret) 47 | self.assertEqual(consumer_key, oauth_method.consumer_key) 48 | self.assertEqual(consumer_secret, oauth_method.consumer_secret) 49 | 50 | def test_options(self): 51 | options = loading.get_plugin_loader('v3oauth1').get_options() 52 | 53 | self.assertEqual( 54 | {o.name for o in options}, 55 | { 56 | 'auth-url', 57 | 'access-key', 58 | 'access-secret', 59 | 'consumer-key', 60 | 'consumer-secret', 61 | }, 62 | ) 63 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/saml2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/extras/saml2/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/saml2/examples/xml/ADFS_fault.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://www.w3.org/2005/08/addressing/soap/fault 4 | urn:uuid:89c47849-2622-4cdc-bb06-1d46c89ed12d 5 | 6 | 7 | 8 | 9 | s:Sender 10 | 11 | a:FailedAuthentication 12 | 13 | 14 | 15 | At least one security token in the message could not be validated. 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/saml2/fixtures/templates/authn_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | $issuer 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/saml2/fixtures/templates/soap_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 12 | 13 | $issuer 14 | 15 | 16 | 17 | 18 | 19 | 23 | ss:mem:6f1f20fafbb38433467e9d477df67615 24 | 25 | 26 | 27 | 34 | 35 | $issuer 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/extras/saml2/utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import os 14 | 15 | from lxml import etree 16 | 17 | from keystoneauth1 import session 18 | from keystoneauth1.tests.unit import utils 19 | 20 | ROOTDIR = os.path.dirname(os.path.abspath(__file__)) 21 | XMLDIR = os.path.join(ROOTDIR, 'examples', 'xml/') 22 | 23 | 24 | def make_oneline(s): 25 | return etree.tostring(etree.XML(s)).replace(b'\n', b'') 26 | 27 | 28 | def _load_xml(filename): 29 | with open(XMLDIR + filename, 'rb') as f: 30 | return f.read() 31 | 32 | 33 | class TestCase(utils.TestCase): 34 | TEST_URL = 'https://keystone:5000/v3' 35 | 36 | def setUp(self): 37 | super().setUp() 38 | self.session = session.Session() 39 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/identity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/identity/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/identity/test_access.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import uuid 14 | 15 | from keystoneauth1 import access 16 | from keystoneauth1 import fixture 17 | from keystoneauth1.identity import access as access_plugin 18 | from keystoneauth1 import plugin 19 | from keystoneauth1 import session 20 | from keystoneauth1.tests.unit import utils 21 | 22 | 23 | class AccessInfoPluginTests(utils.TestCase): 24 | def setUp(self): 25 | super().setUp() 26 | self.session = session.Session() 27 | self.auth_token = uuid.uuid4().hex 28 | 29 | def _plugin(self, **kwargs): 30 | token = fixture.V3Token() 31 | s = token.add_service('identity') 32 | s.add_standard_endpoints(public=self.TEST_ROOT_URL) 33 | 34 | auth_ref = access.create(body=token, auth_token=self.auth_token) 35 | return access_plugin.AccessInfoPlugin(auth_ref, **kwargs) 36 | 37 | def test_auth_ref(self): 38 | plugin_obj = self._plugin() 39 | self.assertEqual( 40 | self.TEST_ROOT_URL, 41 | plugin_obj.get_endpoint( 42 | self.session, service_type='identity', interface='public' 43 | ), 44 | ) 45 | self.assertEqual(self.auth_token, plugin_obj.get_token(session)) 46 | 47 | def test_auth_url(self): 48 | auth_url = 'http://keystone.test.url' 49 | obj = self._plugin(auth_url=auth_url) 50 | 51 | self.assertEqual( 52 | auth_url, 53 | obj.get_endpoint(self.session, interface=plugin.AUTH_INTERFACE), 54 | ) 55 | 56 | def test_invalidate(self): 57 | plugin = self._plugin() 58 | auth_ref = plugin.auth_ref 59 | 60 | self.assertIsInstance(auth_ref, access.AccessInfo) 61 | self.assertFalse(plugin.invalidate()) 62 | self.assertIs(auth_ref, plugin.auth_ref) 63 | 64 | def test_project_auth_properties(self): 65 | plugin = self._plugin() 66 | auth_ref = plugin.auth_ref 67 | 68 | self.assertIsNone(auth_ref.project_domain_id) 69 | self.assertIsNone(auth_ref.project_domain_name) 70 | self.assertIsNone(auth_ref.project_id) 71 | self.assertIsNone(auth_ref.project_name) 72 | 73 | def test_domain_auth_properties(self): 74 | plugin = self._plugin() 75 | auth_ref = plugin.auth_ref 76 | 77 | self.assertIsNone(auth_ref.domain_id) 78 | self.assertIsNone(auth_ref.domain_name) 79 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/identity/test_token.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import uuid 14 | 15 | from keystoneauth1.identity.generic import token 16 | from keystoneauth1.identity import v2 17 | from keystoneauth1.identity import v3 18 | from keystoneauth1.identity.v3 import token as v3_token 19 | from keystoneauth1.tests.unit.identity import utils 20 | 21 | 22 | class TokenTests(utils.GenericPluginTestCase): 23 | PLUGIN_CLASS = token.Token 24 | V2_PLUGIN_CLASS = v2.Token 25 | V3_PLUGIN_CLASS = v3.Token 26 | 27 | def new_plugin(self, **kwargs): 28 | kwargs.setdefault('token', uuid.uuid4().hex) 29 | return super().new_plugin(**kwargs) 30 | 31 | def test_symbols(self): 32 | self.assertIs(v3.Token, v3_token.Token) 33 | self.assertIs(v3.TokenMethod, v3_token.TokenMethod) 34 | 35 | def test_token_cache_id(self): 36 | the_token = uuid.uuid4().hex 37 | project_name = uuid.uuid4().hex 38 | default_domain_id = uuid.uuid4().hex 39 | 40 | a = token.Token( 41 | self.TEST_URL, 42 | token=the_token, 43 | project_name=project_name, 44 | default_domain_id=default_domain_id, 45 | ) 46 | 47 | b = token.Token( 48 | self.TEST_URL, 49 | token=the_token, 50 | project_name=project_name, 51 | default_domain_id=default_domain_id, 52 | ) 53 | 54 | a_id = a.get_cache_id() 55 | b_id = b.get_cache_id() 56 | 57 | self.assertEqual(a_id, b_id) 58 | 59 | c = token.Token( 60 | self.TEST_URL, 61 | token=the_token, 62 | project_name=uuid.uuid4().hex, # different 63 | default_domain_id=default_domain_id, 64 | ) 65 | 66 | c_id = c.get_cache_id() 67 | 68 | self.assertNotEqual(a_id, c_id) 69 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/keystoneauth_fixtures.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | import fixtures 15 | 16 | 17 | class HackingCode(fixtures.Fixture): 18 | """A fixture to house the various code examples. 19 | 20 | Examples contains various keystoneauth hacking style checks. 21 | """ 22 | 23 | oslo_namespace_imports = { 24 | 'code': """ 25 | import oslo.utils 26 | import oslo_utils 27 | import oslo.utils.encodeutils 28 | import oslo_utils.encodeutils 29 | from oslo import utils 30 | from oslo.utils import encodeutils 31 | from oslo_utils import encodeutils 32 | 33 | import oslo.serialization 34 | import oslo_serialization 35 | import oslo.serialization.jsonutils 36 | import oslo_serialization.jsonutils 37 | from oslo import serialization 38 | from oslo.serialization import jsonutils 39 | from oslo_serialization import jsonutils 40 | 41 | import oslo.config 42 | import oslo_config 43 | import oslo.config.cfg 44 | import oslo_config.cfg 45 | from oslo import config 46 | from oslo.config import cfg 47 | from oslo_config import cfg 48 | 49 | import oslo.i18n 50 | import oslo_i18n 51 | import oslo.i18n.log 52 | import oslo_i18n.log 53 | from oslo import i18n 54 | from oslo.i18n import log 55 | from oslo_i18n import log 56 | """, 57 | 'expected_errors': [ 58 | (1, 0, 'K333'), 59 | (3, 0, 'K333'), 60 | (5, 0, 'K333'), 61 | (6, 0, 'K333'), 62 | (9, 0, 'K333'), 63 | (11, 0, 'K333'), 64 | (13, 0, 'K333'), 65 | (14, 0, 'K333'), 66 | (17, 0, 'K333'), 67 | (19, 0, 'K333'), 68 | (21, 0, 'K333'), 69 | (22, 0, 'K333'), 70 | (25, 0, 'K333'), 71 | (27, 0, 'K333'), 72 | (29, 0, 'K333'), 73 | (30, 0, 'K333'), 74 | ], 75 | } 76 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/loading/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/keystoneauth1/tests/unit/loading/__init__.py -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/loading/test_entry_points.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import stevedore 14 | 15 | from keystoneauth1 import loading 16 | from keystoneauth1.tests.unit.loading import utils 17 | 18 | 19 | class EntryPointTests(utils.TestCase): 20 | """Simple test that will check that all entry points are loadable.""" 21 | 22 | def test_all_entry_points_are_valid(self): 23 | errors = [] 24 | 25 | def raise_exception_callback(manager, entrypoint, exc): 26 | error = f"Cannot load '{entrypoint}' entry_point: {exc}'" 27 | errors.append(error) 28 | 29 | stevedore.ExtensionManager( 30 | namespace=loading.PLUGIN_NAMESPACE, 31 | on_load_failure_callback=raise_exception_callback, 32 | ) 33 | 34 | self.assertEqual([], errors) 35 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/loading/test_fixtures.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import uuid 14 | 15 | from oslo_config import fixture as config 16 | 17 | from keystoneauth1 import fixture 18 | from keystoneauth1 import loading 19 | from keystoneauth1 import session 20 | from keystoneauth1.tests.unit import utils 21 | 22 | 23 | class FixturesTests(utils.TestCase): 24 | GROUP = uuid.uuid4().hex 25 | AUTH_TYPE = uuid.uuid4().hex 26 | 27 | def setUp(self): 28 | super().setUp() 29 | self.conf_fixture = self.useFixture(config.Config()) 30 | 31 | # conf loading will still try to read the auth_type from the config 32 | # object and pass that to the get_plugin_loader method. This value will 33 | # typically be ignored and the fake plugin returned regardless of name 34 | # but it could be a useful differentiator and it also ensures that the 35 | # application has called register_auth_conf_options before simply 36 | # returning a fake plugin. 37 | loading.register_auth_conf_options( 38 | self.conf_fixture.conf, group=self.GROUP 39 | ) 40 | 41 | self.conf_fixture.config(auth_type=self.AUTH_TYPE, group=self.GROUP) 42 | 43 | def useLoadingFixture(self, **kwargs): 44 | return self.useFixture(fixture.LoadingFixture(**kwargs)) 45 | 46 | def test_endpoint_resolve(self): 47 | endpoint = "http://%(service_type)s/%(version)s/%(interface)s" 48 | loader = self.useLoadingFixture(endpoint=endpoint) 49 | 50 | endpoint_filter = { 51 | 'service_type': 'compute', 52 | 'service_name': 'nova', 53 | 'version': (2, 1), 54 | 'interface': 'public', 55 | } 56 | 57 | auth = loading.load_auth_from_conf_options( 58 | self.conf_fixture.conf, self.GROUP 59 | ) 60 | sess = session.Session(auth=auth) 61 | 62 | loader_endpoint = loader.get_endpoint(**endpoint_filter) 63 | plugin_endpoint = sess.get_endpoint(**endpoint_filter) 64 | 65 | self.assertEqual("http://compute/2.1/public", loader_endpoint) 66 | self.assertEqual(loader_endpoint, plugin_endpoint) 67 | 68 | def test_conf_loaded(self): 69 | token = uuid.uuid4().hex 70 | endpoint_filter = { 71 | 'service_type': 'compute', 72 | 'service_name': 'nova', 73 | 'version': (2, 1), 74 | } 75 | 76 | loader = self.useLoadingFixture(token=token) 77 | 78 | url = loader.get_endpoint('/path', **endpoint_filter) 79 | 80 | m = self.requests_mock.get(url) 81 | 82 | auth = loading.load_auth_from_conf_options( 83 | self.conf_fixture.conf, self.GROUP 84 | ) 85 | sess = session.Session(auth=auth) 86 | self.assertEqual(self.AUTH_TYPE, auth.auth_type) 87 | 88 | sess.get('/path', endpoint_filter=endpoint_filter) 89 | 90 | self.assertTrue(m.called_once) 91 | 92 | self.assertEqual(token, m.last_request.headers['X-Auth-Token']) 93 | self.assertEqual(loader.project_id, sess.get_project_id()) 94 | self.assertEqual(loader.user_id, sess.get_user_id()) 95 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/loading/test_generic.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import uuid 14 | 15 | from keystoneauth1 import fixture 16 | from keystoneauth1 import identity 17 | from keystoneauth1.loading._plugins.identity import generic 18 | from keystoneauth1 import session 19 | from keystoneauth1.tests.unit.loading import utils 20 | 21 | 22 | class PasswordTests(utils.TestCase): 23 | def test_options(self): 24 | opts = [o.name for o in generic.Password().get_options()] 25 | 26 | allowed_opts = [ 27 | 'username', 28 | 'user-domain-id', 29 | 'user-domain-name', 30 | 'user-id', 31 | 'password', 32 | 'system-scope', 33 | 'domain-id', 34 | 'domain-name', 35 | 'project-id', 36 | 'project-name', 37 | 'project-domain-id', 38 | 'project-domain-name', 39 | 'trust-id', 40 | 'auth-url', 41 | 'default-domain-id', 42 | 'default-domain-name', 43 | ] 44 | 45 | self.assertEqual(set(allowed_opts), set(opts)) 46 | self.assertEqual(len(allowed_opts), len(opts)) 47 | 48 | def test_loads_v3_with_user_domain(self): 49 | auth_url = 'http://keystone.test:5000' 50 | disc = fixture.DiscoveryList(href=auth_url) 51 | sess = session.Session() 52 | self.requests_mock.get(auth_url, json=disc) 53 | 54 | plugin = generic.Password().load_from_options( 55 | auth_url=auth_url, 56 | user_id=uuid.uuid4().hex, 57 | password=uuid.uuid4().hex, 58 | project_id=uuid.uuid4().hex, 59 | user_domain_id=uuid.uuid4().hex, 60 | ) 61 | 62 | inner_plugin = plugin._do_create_plugin(sess) 63 | 64 | self.assertIsInstance(inner_plugin, identity.V3Password) 65 | self.assertEqual(inner_plugin.auth_url, auth_url + '/v3') 66 | 67 | 68 | class TokenTests(utils.TestCase): 69 | def test_options(self): 70 | opts = [o.name for o in generic.Token().get_options()] 71 | 72 | allowed_opts = [ 73 | 'token', 74 | 'system-scope', 75 | 'domain-id', 76 | 'domain-name', 77 | 'project-id', 78 | 'project-name', 79 | 'project-domain-id', 80 | 'project-domain-name', 81 | 'trust-id', 82 | 'auth-url', 83 | 'default-domain-id', 84 | 'default-domain-name', 85 | ] 86 | 87 | self.assertEqual(set(allowed_opts), set(opts)) 88 | self.assertEqual(len(allowed_opts), len(opts)) 89 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/loading/test_opts.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import os 14 | from unittest import mock 15 | 16 | from keystoneauth1.loading import opts 17 | from keystoneauth1.tests.unit.loading import utils 18 | 19 | 20 | class OptTests(utils.TestCase): 21 | def test_argparse_args(self): 22 | opt = opts.Opt('auth-url') 23 | self.assertEqual(['--os-auth-url'], opt.argparse_args) 24 | 25 | def test_argparse_args_with_deprecations(self): 26 | opt = opts.Opt('username', deprecated=[opts.Opt('user-name')]) 27 | self.assertEqual( 28 | ['--os-username', '--os-user-name'], opt.argparse_args 29 | ) 30 | 31 | def test_argparse_envvars(self): 32 | opt = opts.Opt('auth-url') 33 | self.assertEqual(['OS_AUTH_URL'], opt.argparse_envvars) 34 | 35 | def test_argparse_envvars_with_deprecations(self): 36 | opt = opts.Opt('username', deprecated=[opts.Opt('user-name')]) 37 | self.assertEqual(['OS_USERNAME', 'OS_USER_NAME'], opt.argparse_envvars) 38 | 39 | def test_argparse_default(self): 40 | opt = opts.Opt('auth-url') 41 | 42 | with mock.patch.dict( 43 | os.environ, {'OS_AUTH_URL': 'http://1.2.3.4/identity'}, clear=True 44 | ): 45 | self.assertEqual('http://1.2.3.4/identity', opt.argparse_default) 46 | 47 | def test_argparse_default_with_deprecations(self): 48 | opt = opts.Opt('username', deprecated=[opts.Opt('user-name')]) 49 | 50 | with mock.patch.dict( 51 | os.environ, {'OS_USER_NAME': 'superuser'}, clear=True 52 | ): 53 | self.assertEqual('superuser', opt.argparse_default) 54 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/loading/utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import functools 14 | from unittest import mock 15 | import uuid 16 | 17 | 18 | from keystoneauth1 import loading 19 | from keystoneauth1.loading import base 20 | from keystoneauth1 import plugin 21 | from keystoneauth1.tests.unit import utils 22 | 23 | 24 | class TestCase(utils.TestCase): 25 | GROUP = 'auth' 26 | V2PASS = 'v2password' 27 | V3TOKEN = 'v3token' 28 | 29 | a_int = 88 30 | a_float = 88.8 31 | a_bool = False 32 | 33 | TEST_VALS = {'a_int': a_int, 'a_float': a_float, 'a_bool': a_bool} 34 | 35 | def assertTestVals(self, plugin, vals=TEST_VALS): 36 | for k, v in vals.items(): 37 | self.assertEqual(v, plugin[k]) 38 | 39 | 40 | def create_plugin(opts=[], token=None, endpoint=None): 41 | class Plugin(plugin.BaseAuthPlugin): 42 | def __init__(self, **kwargs): 43 | self._data = kwargs 44 | 45 | def __getitem__(self, key): 46 | return self._data[key] 47 | 48 | def get_token(self, *args): 49 | return token 50 | 51 | def get_endpoint(self, *args, **kwargs): 52 | return endpoint 53 | 54 | class Loader(loading.BaseLoader): 55 | @property 56 | def plugin_class(self): 57 | return Plugin 58 | 59 | def get_options(self): 60 | return opts 61 | 62 | return Plugin, Loader 63 | 64 | 65 | class BoolType: 66 | def __eq__(self, other): 67 | """Define equiality for many bool types.""" 68 | # hack around oslo.config equality comparison 69 | return type(self) is type(other) 70 | 71 | def __call__(self, value): 72 | return str(value).lower() in ('1', 'true', 't', 'yes', 'y') 73 | 74 | 75 | INT_DESC = 'test int' 76 | FLOAT_DESC = 'test float' 77 | BOOL_DESC = 'test bool' 78 | STR_DESC = 'test str' 79 | STR_DEFAULT = uuid.uuid4().hex 80 | 81 | 82 | MockPlugin, MockLoader = create_plugin( 83 | endpoint='http://test', 84 | token='aToken', 85 | opts=[ 86 | loading.Opt('a-int', default=3, type=int, help=INT_DESC), 87 | loading.Opt('a-bool', type=BoolType(), help=BOOL_DESC), 88 | loading.Opt('a-float', type=float, help=FLOAT_DESC), 89 | loading.Opt('a-str', help=STR_DESC, default=STR_DEFAULT), 90 | ], 91 | ) 92 | 93 | 94 | class MockManager: 95 | def __init__(self, driver): 96 | self.driver = driver 97 | 98 | 99 | def mock_plugin(loader=MockLoader): 100 | def _wrapper(f): 101 | @functools.wraps(f) 102 | def inner(*args, **kwargs): 103 | with mock.patch.object(base, 'get_plugin_loader') as m: 104 | m.return_value = loader() 105 | args = list(args) + [m] 106 | return f(*args, **kwargs) 107 | 108 | return inner 109 | 110 | return _wrapper 111 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/matchers.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 OpenStack Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from lxml import etree 16 | from testtools import matchers 17 | 18 | 19 | class XMLEquals: 20 | """Parses two XML documents from strings and compares the results.""" 21 | 22 | def __init__(self, expected): 23 | self.expected = expected 24 | 25 | def __str__(self): 26 | """Return string representation of xml document info.""" 27 | return f"{self.__class__.__name__}({self.expected!r})" 28 | 29 | def match(self, other): 30 | def xml_element_equals(expected_doc, observed_doc): 31 | """Test whether two XML documents are equivalent. 32 | 33 | This is a recursive algorithm that operates on each element in 34 | the hierarchy. Siblings are sorted before being checked to 35 | account for two semantically equivalent documents where siblings 36 | appear in different document order. 37 | 38 | The sorting algorithm is a little weak in that it could fail for 39 | documents where siblings at a given level are the same, but have 40 | different children. 41 | 42 | """ 43 | if expected_doc.tag != observed_doc.tag: 44 | return False 45 | 46 | if expected_doc.attrib != observed_doc.attrib: 47 | return False 48 | 49 | def _sorted_children(doc): 50 | return sorted(doc.getchildren(), key=lambda el: el.tag) 51 | 52 | expected_children = _sorted_children(expected_doc) 53 | observed_children = _sorted_children(observed_doc) 54 | 55 | if len(expected_children) != len(observed_children): 56 | return False 57 | 58 | for expected_el, observed_el in zip( 59 | expected_children, observed_children 60 | ): 61 | if not xml_element_equals(expected_el, observed_el): 62 | return False 63 | 64 | return True 65 | 66 | parser = etree.XMLParser(remove_blank_text=True) 67 | expected_doc = etree.fromstring(self.expected.strip(), parser) 68 | observed_doc = etree.fromstring(other.strip(), parser) 69 | 70 | if xml_element_equals(expected_doc, observed_doc): 71 | return 72 | 73 | return XMLMismatch(self.expected, other) 74 | 75 | 76 | class XMLMismatch(matchers.Mismatch): 77 | def __init__(self, expected, other): 78 | self.expected = expected 79 | self.other = other 80 | 81 | def describe(self): 82 | def pretty_xml(xml): 83 | parser = etree.XMLParser(remove_blank_text=True) 84 | doc = etree.fromstring(xml.strip(), parser) 85 | return etree.tostring( 86 | doc, encoding='utf-8', pretty_print=True 87 | ).decode('utf-8') 88 | 89 | return f'expected =\n{pretty_xml(self.expected)}\nactual =\n{pretty_xml(self.other)}' 90 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_betamax_serializer.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import json 14 | import os 15 | 16 | import testtools 17 | import yaml 18 | 19 | from keystoneauth1.fixture import serializer 20 | 21 | 22 | class TestBetamaxSerializer(testtools.TestCase): 23 | TEST_FILE = os.path.join( 24 | os.path.dirname(os.path.abspath(__file__)), 25 | 'data', 26 | 'ksa_betamax_test_cassette.yaml', 27 | ) 28 | TEST_JSON = os.path.join( 29 | os.path.dirname(os.path.abspath(__file__)), 30 | 'data', 31 | 'ksa_serializer_data.json', 32 | ) 33 | 34 | def setUp(self): 35 | super().setUp() 36 | self.serializer = serializer.YamlJsonSerializer() 37 | 38 | def test_deserialize(self): 39 | data = self.serializer.deserialize(open(self.TEST_FILE).read()) 40 | request = data['http_interactions'][0]['request'] 41 | self.assertEqual( 42 | 'http://keystoneauth-betamax.test/v2.0/tokens', request['uri'] 43 | ) 44 | payload = json.loads(request['body']['string']) 45 | self.assertEqual('test_tenant_name', payload['auth']['tenantName']) 46 | 47 | def test_serialize(self): 48 | data = json.loads(open(self.TEST_JSON).read()) 49 | serialized = self.serializer.serialize(data) 50 | data = yaml.safe_load(serialized) 51 | request = data['http_interactions'][0]['request'] 52 | self.assertEqual( 53 | 'http://keystoneauth-betamax.test/v2.0/tokens', request['uri'] 54 | ) 55 | payload = json.loads(request['body']['string']) 56 | self.assertEqual('test_tenant_name', payload['auth']['tenantName']) 57 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_fair_sempahore.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import queue 14 | from threading import Thread 15 | from timeit import default_timer as timer 16 | from unittest import mock 17 | 18 | import testtools 19 | 20 | from keystoneauth1 import _fair_semaphore 21 | 22 | 23 | class SemaphoreTests(testtools.TestCase): 24 | def _thread_worker(self): 25 | while True: 26 | # get returns the Item, but we don't care about the value so we 27 | # purposely don't assign it to anything. 28 | self.q.get() 29 | with self.s: 30 | self.mock_payload.do_something() 31 | self.q.task_done() 32 | 33 | # Have 5 threads do 10 different "things" coordinated by the fair 34 | # semaphore. 35 | def _concurrency_core(self, concurrency, delay): 36 | self.s = _fair_semaphore.FairSemaphore(concurrency, delay) 37 | 38 | self.q = queue.Queue() 39 | for i in range(5): 40 | t = Thread(target=self._thread_worker) 41 | t.daemon = True 42 | t.start() 43 | 44 | for item in range(0, 10): 45 | self.q.put(item) 46 | 47 | self.q.join() 48 | 49 | def setUp(self): 50 | super().setUp() 51 | self.mock_payload = mock.Mock() 52 | 53 | # We should be waiting at least 0.1s between operations, so 54 | # the 10 operations must take at *least* 1 second 55 | def test_semaphore_no_concurrency(self): 56 | start = timer() 57 | self._concurrency_core(None, 0.1) 58 | end = timer() 59 | self.assertTrue((end - start) > 1.0) 60 | self.assertEqual(self.mock_payload.do_something.call_count, 10) 61 | 62 | def test_semaphore_single_concurrency(self): 63 | start = timer() 64 | self._concurrency_core(1, 0.1) 65 | end = timer() 66 | self.assertTrue((end - start) > 1.0) 67 | self.assertEqual(self.mock_payload.do_something.call_count, 10) 68 | 69 | def test_semaphore_multiple_concurrency(self): 70 | start = timer() 71 | self._concurrency_core(5, 0.1) 72 | end = timer() 73 | self.assertTrue((end - start) > 1.0) 74 | self.assertEqual(self.mock_payload.do_something.call_count, 10) 75 | 76 | # do some high speed tests; I don't think we can really assert 77 | # much about these other than they don't deadlock... 78 | def test_semaphore_fast_no_concurrency(self): 79 | self._concurrency_core(None, 0.0) 80 | 81 | def test_semaphore_fast_single_concurrency(self): 82 | self._concurrency_core(1, 0.0) 83 | 84 | def test_semaphore_fast_multiple_concurrency(self): 85 | self._concurrency_core(5, 0.0) 86 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_hacking_checks.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import textwrap 14 | from unittest import mock 15 | 16 | import pycodestyle 17 | import testtools 18 | 19 | from keystoneauth1.hacking import checks 20 | from keystoneauth1.tests.unit import keystoneauth_fixtures 21 | 22 | 23 | class TestCheckOsloNamespaceImports(testtools.TestCase): 24 | # We are patching pycodestyle so that only the check under test is actually 25 | # installed. 26 | @mock.patch( 27 | 'pycodestyle._checks', 28 | {'physical_line': {}, 'logical_line': {}, 'tree': {}}, 29 | ) 30 | def run_check(self, code): 31 | pycodestyle.register_check(checks.check_oslo_namespace_imports) 32 | 33 | lines = textwrap.dedent(code).strip().splitlines(True) 34 | 35 | checker = pycodestyle.Checker(lines=lines) 36 | checker.check_all() 37 | checker.report._deferred_print.sort() 38 | return checker.report._deferred_print 39 | 40 | def assert_has_errors(self, code, expected_errors=None): 41 | actual_errors = [e[:3] for e in self.run_check(code)] 42 | self.assertEqual(expected_errors or [], actual_errors) 43 | 44 | def test(self): 45 | code_ex = self.useFixture(keystoneauth_fixtures.HackingCode()) 46 | code = code_ex.oslo_namespace_imports['code'] 47 | errors = code_ex.oslo_namespace_imports['expected_errors'] 48 | self.assert_has_errors(code, expected_errors=errors) 49 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_http_basic.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1 import http_basic 14 | from keystoneauth1.loading._plugins import http_basic as loader 15 | from keystoneauth1 import session 16 | from keystoneauth1.tests.unit import utils 17 | 18 | 19 | class HTTPBasicAuthTest(utils.TestCase): 20 | TEST_URL = 'http://server/prefix' 21 | 22 | def test_basic_case(self): 23 | self.requests_mock.get(self.TEST_URL, text='body') 24 | 25 | a = http_basic.HTTPBasicAuth(username='myName', password='myPassword') 26 | s = session.Session(auth=a) 27 | 28 | data = s.get(self.TEST_URL, authenticated=True) 29 | 30 | self.assertEqual(data.text, 'body') 31 | self.assertRequestHeaderEqual( 32 | 'Authorization', 'Basic bXlOYW1lOm15UGFzc3dvcmQ=' 33 | ) 34 | self.assertIsNone(a.get_endpoint(s)) 35 | 36 | def test_basic_options(self): 37 | opts = loader.HTTPBasicAuth().get_options() 38 | self.assertEqual( 39 | ['username', 'password', 'endpoint'], [o.name for o in opts] 40 | ) 41 | 42 | def test_get_endpoint(self): 43 | a = http_basic.HTTPBasicAuth(endpoint=self.TEST_URL) 44 | s = session.Session(auth=a) 45 | self.assertEqual(self.TEST_URL, a.get_endpoint(s)) 46 | 47 | def test_get_endpoint_with_override(self): 48 | a = http_basic.HTTPBasicAuth(endpoint=self.TEST_URL) 49 | s = session.Session(auth=a) 50 | self.assertEqual('foo', a.get_endpoint(s, endpoint_override='foo')) 51 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_noauth.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from keystoneauth1.loading._plugins import noauth as loader 14 | from keystoneauth1 import noauth 15 | from keystoneauth1 import session 16 | from keystoneauth1.tests.unit import utils 17 | 18 | 19 | class NoAuthTest(utils.TestCase): 20 | NOAUTH_TOKEN = 'notused' 21 | TEST_URL = 'http://server/prefix' 22 | 23 | def test_basic_case(self): 24 | self.requests_mock.get(self.TEST_URL, text='body') 25 | 26 | a = noauth.NoAuth() 27 | s = session.Session(auth=a) 28 | 29 | data = s.get(self.TEST_URL, authenticated=True) 30 | 31 | self.assertEqual(data.text, 'body') 32 | self.assertRequestHeaderEqual('X-Auth-Token', self.NOAUTH_TOKEN) 33 | self.assertIsNone(a.get_endpoint(s)) 34 | 35 | def test_noauth_options(self): 36 | opts = loader.NoAuth().get_options() 37 | self.assertEqual(['endpoint'], [o.name for o in opts]) 38 | 39 | def test_get_endpoint(self): 40 | a = noauth.NoAuth(endpoint=self.TEST_URL) 41 | s = session.Session(auth=a) 42 | self.assertEqual(self.TEST_URL, a.get_endpoint(s)) 43 | 44 | def test_get_endpoint_with_override(self): 45 | a = noauth.NoAuth(endpoint=self.TEST_URL) 46 | s = session.Session(auth=a) 47 | self.assertEqual('foo', a.get_endpoint(s, endpoint_override='foo')) 48 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_token_endpoint.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from testtools import matchers 14 | 15 | from keystoneauth1.loading._plugins import admin_token as loader 16 | from keystoneauth1 import session 17 | from keystoneauth1.tests.unit import utils 18 | from keystoneauth1 import token_endpoint 19 | 20 | 21 | class TokenEndpointTest(utils.TestCase): 22 | TEST_TOKEN = 'aToken' 23 | TEST_URL = 'http://server/prefix' 24 | 25 | def test_basic_case(self): 26 | self.requests_mock.get(self.TEST_URL, text='body') 27 | 28 | a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) 29 | s = session.Session(auth=a) 30 | 31 | data = s.get(self.TEST_URL, authenticated=True) 32 | 33 | self.assertEqual(data.text, 'body') 34 | self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) 35 | 36 | def test_basic_endpoint_case(self): 37 | self.stub_url('GET', ['p'], text='body') 38 | a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) 39 | s = session.Session(auth=a) 40 | 41 | data = s.get( 42 | '/p', authenticated=True, endpoint_filter={'service': 'identity'} 43 | ) 44 | 45 | self.assertEqual(self.TEST_URL, a.get_endpoint(s)) 46 | self.assertEqual('body', data.text) 47 | self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) 48 | 49 | def test_token_endpoint_user_id(self): 50 | a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) 51 | s = session.Session() 52 | 53 | # we can't know this information about this sort of plugin 54 | self.assertIsNone(a.get_user_id(s)) 55 | self.assertIsNone(a.get_project_id(s)) 56 | 57 | 58 | class AdminTokenTest(utils.TestCase): 59 | def test_token_endpoint_options(self): 60 | opt_names = [opt.name for opt in loader.AdminToken().get_options()] 61 | 62 | self.assertThat(opt_names, matchers.HasLength(2)) 63 | 64 | self.assertIn('token', opt_names) 65 | self.assertIn('endpoint', opt_names) 66 | 67 | def test_token_endpoint_deprecated_options(self): 68 | endpoint_opt = [ 69 | opt 70 | for opt in loader.AdminToken().get_options() 71 | if opt.name == 'endpoint' 72 | ][0] 73 | 74 | opt_names = [opt.name for opt in endpoint_opt.deprecated] 75 | 76 | self.assertEqual(['url'], opt_names) 77 | -------------------------------------------------------------------------------- /keystoneauth1/tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import testtools 14 | 15 | from keystoneauth1 import _utils 16 | 17 | 18 | class UtilsTests(testtools.TestCase): 19 | def test_get_logger(self): 20 | self.assertEqual( 21 | 'keystoneauth.tests.unit.test_utils', 22 | _utils.get_logger(__name__).name, 23 | ) 24 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.mypy] 2 | python_version = "3.10" 3 | show_column_numbers = true 4 | show_error_context = true 5 | ignore_missing_imports = true 6 | follow_imports = "normal" 7 | check_untyped_defs = true 8 | warn_unused_ignores = true 9 | warn_return_any = true 10 | warn_unused_configs = true 11 | warn_redundant_casts = true 12 | strict_equality = true 13 | disallow_untyped_decorators = true 14 | disallow_any_generics = true 15 | disallow_subclassing_any = true 16 | disallow_untyped_calls = true 17 | disallow_incomplete_defs = true 18 | disallow_untyped_defs = true 19 | no_implicit_reexport = true 20 | extra_checks = true 21 | # keep this in-sync with 'mypy.exclude' in '.pre-commit-config.yaml' 22 | exclude = ''' 23 | (?x)( 24 | doc 25 | | examples 26 | | releasenotes 27 | ) 28 | ''' 29 | 30 | [[tool.mypy.overrides]] 31 | module = ["keystoneauth1.tests.unit.*"] 32 | ignore_errors = true 33 | 34 | [[tool.mypy.overrides]] 35 | module = [ 36 | "keystoneauth1.fixture.*", 37 | "keystoneauth1.hacking.*", 38 | ] 39 | disallow_subclassing_any = false 40 | disallow_untyped_defs = false 41 | disallow_untyped_calls = false 42 | 43 | [tool.ruff] 44 | line-length = 79 45 | target-version = "py310" 46 | 47 | [tool.ruff.lint] 48 | # enable the following rule classes: 49 | # 50 | # C4: https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 51 | # E: https://docs.astral.sh/ruff/rules/#pycodestyle-e-w 52 | # F: https://docs.astral.sh/ruff/rules/#pyflakes-f 53 | # UP: https://docs.astral.sh/ruff/rules/#pyupgrade-up 54 | select = ["C4", "E4", "E7", "E9", "F", "UP"] 55 | 56 | [tool.ruff.format] 57 | quote-style = "preserve" 58 | docstring-code-format = true 59 | skip-magic-trailing-comma = true 60 | -------------------------------------------------------------------------------- /releasenotes/notes/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/releasenotes/notes/.placeholder -------------------------------------------------------------------------------- /releasenotes/notes/1583780-700f99713e06324e.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Added a new OidcAccessToken plugin, accessible via the 'v3oidcaccesstoken' 4 | entry point, making possible to authenticate using an existing OpenID 5 | Connect Access token. 6 | fixes: 7 | - > 8 | [`bug 1583780 `_] 9 | OpenID connect support should include authenticating using directly an access token. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/add-oidc-client-credentials-2be065926ba4b849.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add support for the Client Credentials OpenID Connect 4 | grant type. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/add-oidc-discovery-document-support-b07fe54f83286d62.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - > 4 | Add support for the `OpenID Connect Discovery Document 5 | `_ 6 | into the OpenID Connect related plugins. Now it is possible to only pass the 7 | `discovery-url` option and the plugins will try to fetch the required 8 | metadata from there. 9 | fixes: 10 | - > 11 | [`bug 1583682 `_] 12 | OpenID Connect plugins should support OpenID Connect Discovery. 13 | -------------------------------------------------------------------------------- /releasenotes/notes/add-otp-support-to-v3oidcpassword-plugin-520160b14e1fcc57.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add support to OTP in the v3OIDCpassword plugin, to enable this feature, 5 | the user must configure the environment variable OS_IDP_OTP_KEY with the name 6 | of the OTP key that the Identity Provider expects while generating the 7 | access token. E.g. OS_IDP_OTP_KEY=totp 8 | -------------------------------------------------------------------------------- /releasenotes/notes/add-prompt-to-opt-d083acc357a7f07b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Add the prompt parameter to loader Opts 4 | features: 5 | - The prompt parameter was added to the Opts provided by auth plugins. The 6 | presence of the prompt parameter on an Option will indicate to plugin 7 | loaders that it is ok to prompt the user for input for this parameter if 8 | none is provided initially. Actual implementation of this prompting 9 | mechanism will be handled by the individual loaders such as 10 | os-client-config. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/add-totp-auth-plugin-0650d220899c25b7.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - > 4 | [`blueprint totp-auth `_] 5 | Add an auth plugin to handle Time-Based One-Time Password (TOTP) 6 | authentication via the ``totp`` method. This new plugin will accept the 7 | following identity options: 8 | 9 | - ``user-id``: user ID 10 | - ``username``: username 11 | - ``user-domain-id``: user's domain ID 12 | - ``user-domain-name``: user's domain name 13 | - ``passcode``: passcode generated by TOTP app or device 14 | 15 | User is uniquely identified by either ``user-id`` or combination of 16 | ``username`` and ``user-domain-id`` or ``user-domain-name``. 17 | -------------------------------------------------------------------------------- /releasenotes/notes/add-typing-617a487a60de0b86.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | All modules except for ``keystoneauth1.fixtures`` and 5 | ``keystoneauth1.hacking`` now provide full type hints. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/additional-headers-f2d16f85f5abe942.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Allow specifying additional_headers to the session and the adapter to add 4 | headers to all requests that pass through these objects. 5 | features: 6 | - Add the ability to provide additional_headers to the session and adapter 7 | object. This will allow clients particularly to provide additional ways to 8 | identify their requests. It will also hopefully provide an intermediate way 9 | to handle setting microversions until we support them directly with 10 | keystoneauth. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/allow_version_hack-flag-9b53b72d9b084c04.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - A new flag `allow_version_hack` was added to identity plugins and the 4 | adapter which will allow a client to opt out of making guesses at the 5 | version url page of a service. This means that if a deployment is 6 | misconfigured and the service catalog contains a versioned endpoint that 7 | does not match the requested version the request will fail. This will be 8 | useful in beginning to require correctly deployed catalogs rather than 9 | continue to hide the problem. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/api-sig-error-guideline-handler.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Fix handling of HTTP error payloads that conform to the API SIG 4 | formatting guidelines. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/basic-http-auth-45bea4298209df75.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | A new ``http_basic`` auth plugin is added which enables HTTP Basic 5 | authentication for standalone services. Like the ``noauth`` plugin, the 6 | ``endpoint`` needs to be specified explicitly, along with the 7 | ``username`` and ``password``. -------------------------------------------------------------------------------- /releasenotes/notes/bp-application-credentials-416a1f8bb2311e04.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | [`blueprint application-credentials `_] 5 | Support for authentication via an application credential has been added. 6 | Keystoneauth can now be used to authenticate to Identity servers that 7 | support application credentials. 8 | -------------------------------------------------------------------------------- /releasenotes/notes/bp-oauth2-client-credentials-ext-06271700d4f33a7e.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | [`blueprint oauth2-client-credentials-ext `_] 5 | Added a new OAuth2ClientCredential plugin, accessible via the 6 | 'v3oauth2clientcredential' entry point, making possible to authenticate 7 | using an application credentials as an OAuth2.0 client credentials. 8 | Keystoneauth can now be used to access the OpenStack APIs that use the 9 | keystone middleware to support OAuth2.0 client credentials authentication 10 | through the keystone identity server. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/bp-support-oauth2-mtls-177cda05265ae65c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | [`blueprint support-oauth2-mtls `_] 5 | Added a new OAuth2mTlsClientCredential plugin, accessible via the 6 | 'v3oauth2mtlsclientcredential' entry point, making possible to authenticate 7 | using an OAuth 2.0 Mutual-TLS client credentials. Keystoneauth can now 8 | be used to access the OpenStack APIs that use the keystone middleware to 9 | support OAuth2.0 mutual-TLS client authentication through the keystone 10 | identity server. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/bp-system-scope-29e9c597039ddb1e.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | [`blueprint system-scope `_] 5 | Keystoneauth now has the ability to authenticate for system-scoped tokens, 6 | which were implemented during the Queens development cycle. System-scoped 7 | tokens will eventually be required to separate system-level APIs from 8 | project-level APIs, allowing for better security via scoped RBAC. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1582774-49af731b6dfc6f2f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Fix passing scope parameters in Oidc* auth plugins. 4 | [Bug `1582774 `_] 5 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1614688-c4a1bd54f4ba5644.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | HTTP connections work under Windows Subsystem for Linux 4 | fixes: 5 | - > 6 | [`bug 1614688 `_] 7 | HTTP connections were failing under Windows subsystem for Linux because 8 | TCP_KEEPCNT was being set and that environment does not support such 9 | override yet. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - > 4 | [`bug 1616105 `_] 5 | Only log the response body when the ``Content-Type`` header is set to 6 | ``application/json``. This avoids logging large binary objects (such as 7 | images). Other ``Content-Type`` will not be logged. Additional 8 | ``Content-Type`` strings can be added as required. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1654847-acdf9543158329ec.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | The ``X-Service-Token`` header value is now properly masked, and is 5 | displayed as a hash value, in the log. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1689424-set-adfspassword-endpointreference-f186d84a54007b09.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Allow setting EndpointReference in ADFSPassword 4 | features: 5 | - > 6 | Add the ability to specify the WS-Policy EndpointReference used in the 7 | ADFSPassword plugin's RequestSecurityToken message via the 8 | 'service-provider-entity-id' option. Also added 'identity-provider-url' 9 | option which was required, but missing from option list. 10 | fixes: 11 | - > 12 | [`bug 1689424 `_] 13 | Allow setting EndpointReference in ADFSPassword. 14 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1733052-1b4af3b3fe1b05bb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - > 4 | [`bug 1733052 `_] 5 | Now the version discovery mechanism only fetches the version info from 6 | server side if the versioned url has been overrode. So that the request 7 | url's path won't be changed completely. 8 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1766235wq-0de60d0f996c6bfb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | [`bug 1766235 `_] 5 | Fixed an issue where passing headers in as bytes rather than strings 6 | would cause a sorting issue. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1839748-5d8dfc99c43aaefc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | [`bug 1839748 `_] 5 | Keystoneauth now supports MFA authentication and Auth Receipts. 6 | Responses from Keystone containing and auth receipt will now 7 | raise a ``MissingAuthMethods`` exception which will contain the 8 | auth receipt itself, and information about the missing methods. 9 | There are now also ways to easily do more than one method when 10 | authenticating to Keystone and those have been documented. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1840235-ef2946d149ac329c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | [`feature bug 1840235 `_] 5 | Adds ``connect_retries`` to Session.__init__(), that can then be used 6 | by projects when creating session objects, to set the required number of 7 | retries for new connection requests. This would specifically help avoid 8 | a scalability issue that results in number of ConnectTimeout errors when 9 | doing endpoint discovery and fetching roles using an auth plugin under 10 | heavy load. This still allows for it to be overridden per service with 11 | the adapter interface. 12 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1876317-1db97d1b12a3e4b4.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | [`bug 1876317 `_] 5 | The v3 authentication plugins now attempt to add /v3 to the token path if 6 | it's not present on the authentication URL. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1998366-27cd486b46fb56b0.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | [`bug 1998366 `_] 5 | Federated auth plugins now can work with unversioned auth url 6 | (e.g. "http://keystone"). 7 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-2053965-b9717c6a8c058956.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | [`bug 2053965 `_] 5 | OIDC Device Authorization Flow: In accordance with RFC8628, for public 6 | clients that do not have a client_secret, the client_id is included in 7 | the request bodies. 8 | -------------------------------------------------------------------------------- /releasenotes/notes/cache-trailing-slash-3663c86cd9754379.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fixed an issue where https://example.com and https://example.com/ were 5 | being treated as different urls in the discovery cache resulting in a 6 | second unneeded discovery call when someone sets an ``endpoint_override`` 7 | that didn't match the trailing-slash form given by that service's 8 | discovery document. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/cleanup-session-on-delete-1ed6177d4c5c1f83.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - > 4 | [`bug 1838704 `_] 5 | When consuming keystoneauth1.session.Session, if a requests session is not 6 | provided one is created. The Session used for requests may result in a 7 | ResourceWarning being generated if it is not properly closed. The code 8 | has been updated to close the session correctly when the Session object 9 | is deleted. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/client-side-rate-limiting-dec43fc9b54f5b70.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Support added for client-side rate limiting. Two new parameters now 5 | exist for ``keystoneauth1.adapter.Adapter``. ``rate`` expresses a 6 | maximum rate at which to execute requests. ``parallel_limit`` allows 7 | for the creation of a semaphore to control the maximum number of 8 | requests that can be active at any one given point in time. 9 | Both default to ``None`` which has the normal behavior or not limiting 10 | requests in any manner. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/collect-timing-85f007f0d86c8b26.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Added ``collect_timing`` option to ``keystoneauth1.session.Session``. 5 | The option, which is off by default, causes the ``Session`` to collect 6 | API timing information for every call it makes. Methods ``get_timings`` 7 | and ``reset_timings`` have been added to allow getting and clearing the 8 | data. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-oidc-grant_type-parameter-79ca58f56238a615.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | The OIDC plugins no longer accept a ``grant_type`` parameter. This was 5 | deprecated in 2.10.0 (Newton) and has now been removed. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-py-2-7-f90c67a5db0dfeb8.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Python 2.7 support has been dropped. Last release of keystoneauth 5 | to support python 2.7 is OpenStack Train. The minimum version of Python now 6 | supported is Python 3.6. -------------------------------------------------------------------------------- /releasenotes/notes/drop-python-3-6-and-3-7-c407d5898c5eafec.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Python 3.6 & 3.7 support has been dropped. The minimum version of Python 5 | now supported is Python 3.8. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-python-3.5-362bb9d47f830353.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Python 3.5 is no longer supported. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-python-39-cb01f8d8ce6dc278.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Support for Python 3.9 has been dropped. The minimum version of Python now 5 | supported in 3.10. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-python38-cb0b045f67bf8a1b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Support for Python 3.8 has been dropped. The minimum version of Python now 5 | supported in 3.9. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/drops-url-parameters-on-redirect-13951b4a4c830d0f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fixes a condition where URL parameters would be appended to a 5 | new URL discovered via a redirect. This was resulting in arguments 6 | being duplicated on requests to the new server being redirected to. 7 | URL redirects are intended to redirect the requester to the final 8 | location, and generally include a fully formatted final destination 9 | URL, which would include URL parameters. URL parameters are now dropped 10 | when attempting to issue a request once redirected. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/expose-endpoint-status-6195a6b76d8a8de8.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Added a 'status' field to the `EndpointData` object which contains a 5 | canonicalized version of the information in the status field of discovery 6 | documents. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/filter-versions-service-type-763af68092344b7a.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Added ability to filter the results of ``get_all_version_data`` by 5 | service-type. 6 | - | 7 | Added ``get_all_version_data`` to ``adapter.Adapter`` that uses the 8 | adapter's ``service_type`` to filter the version data fetched. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/fix-get-all-version-data-a01ee58524755b9b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | The docstring for ``keystoneauth1.session.Session.get_all_version_data`` 5 | correctly listed ``'public'`` as the default value, but the argument list 6 | had ``None``. The default has been fixed to match the documented value. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/get-auth-ref-7418e13bd0942060.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fixes missing ``get_auth_ref`` call for the ``none`` and ``http_basic`` 5 | authentication plugins. The implementation simply returns ``None``. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/global_request_id-per-request-bd66c7e0f1a71d9f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The ``X-Openstack-Request-Id`` header can now be set per-request via a 5 | ``global_request_id`` kwarg to ``Adapter`` and ``Session`` request methods 6 | (``request()``, ``get()``, ``put()``, etc.) 7 | -------------------------------------------------------------------------------- /releasenotes/notes/improve-http-error-handling.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Add logic to handle HTTP error responses that do not conform to a known 4 | schema. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/ironic-discovery-fe41793ef97027bf.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | A workaround for misformed discovery documents was being applied too 5 | soon causing ironic discovery documents to be mistakenly ignored. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/ironic-microversions-a69bf92ab21f0cf5.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fixed support for detecting microversion ranges on older Ironic 5 | installations. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/ksa_2.2.0-81145229d4b43043.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - > 4 | [`bug 1527131 `_] 5 | Do not provide socket values for OSX and Windows. 6 | other: 7 | - Added a betamax fixture for keystoneauth sessions. 8 | - Added a RFC 7231 compliant user agent string. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/microversion-header-support-901acd820a21d788.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Added support for specifying a microversion to use on 4 | a given REST request. The microversion can be specified 5 | on session request calls and a default can be set on 6 | Adapter construction. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/noauth-discovery-c26d82a32c36d41d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Fixes ``get_api_major_version`` for non-keystone authentication methods 5 | when the provided endpoint is not versioned. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/none-auth-dab13ab9af6f5c86.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | A new ``none`` auth plugin is added with purpose to simplify loading 5 | clients from configuration file options. 6 | It does not accept any arguments and sets the token to 'notused'. 7 | It does not have any endpoint/url associated with it, 8 | and thus must be used together with ``adapter.Adapter``'s 9 | ``endpoint_override`` option to instantiate a session for client 10 | to a service that is deployed in noauth/standalone mode. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/oslo-config-split-loggers-6bda266d657fe921.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Added ``split-loggers`` option to the oslo.config Session options. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/retries-limit-dbaedcb3207934ae.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | The retry interval for retries enabled by ``connect_retries`` and 5 | ``status_code_retries`` is now limited at 60 seconds. Previously it would 6 | grow exponentially. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/retries-options-99e4dbc240941557.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The Adapter parameters ``connect_retries`` and ``status_code_retries`` can 5 | now be set via configuration options ``connect-retries`` and 6 | ``status-code-retries`` accordingly. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/retry-authenticated-discovery-19c4354ff983f507.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Retry version discovery with auth token when the initial request 5 | throws 401 Unauthorized. There are some services that are erroneously 6 | defaulting to authenticated discovery, and this allows discovery 7 | to work properly on them. 8 | upgrade: 9 | - | 10 | If keystoneauth and openstacksdk are both in use and keystoneauth 11 | is upgraded to this release **before** upgrading openstacksdk to 12 | ``0.36.1`` or later, creation of ServerGroup objects with policies 13 | and use of Ansible Inventory could be adversely affected. See 14 | https://review.opendev.org/#/c/685999/ for more details. 15 | -------------------------------------------------------------------------------- /releasenotes/notes/retry-delay-68d0c0a1dffcf2fd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Allows configuring fixed retry delay for connection and status code retries 5 | via the new parameters ``connect_retry_delay`` and 6 | ``status_code_retry_delay`` accordingly. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/serice-type-aliases-249454829c57f39a.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Added support for service-type aliases as defined in the Service Types 5 | Authority when doing catalog lookups. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/status-code-retries-75052a43efa4edb2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Addes support for retrying certain HTTP status codes when doing requests 5 | via the new ``status_code_retries`` and ``retriable_status_codes`` 6 | parameters for ``Session`` and ``Adapter``. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/support-api-wg-discovery-2cb4b0186619e124.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Added support for the API Working Group recommendations 4 | on service and version discovery. New methods on 5 | Session and Adapter, "get_endpoint_data" will return 6 | endpoint metadata including microversion information. 7 | Additionally, versions can be requested with a range 8 | and with the string "latest", and interface values 9 | can be given as a list in case a user wants to express 10 | a 'best available' set of preferences. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/user-agent-generation-b069100508c06177.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Allow adding client and application name and version to the session and 4 | adapter that will generate a userful user agent string. 5 | features: 6 | - You can specify a ``app_name`` and ``app_version`` when creating a 7 | session. This information will be encoded into the user agent. 8 | - You can specify a ``client_name`` and ``client_version`` when creating an 9 | adapter. This will be handled by client libraries and incluced into the user 10 | agent. 11 | - Libraries like shade that modify the way requests are made can add 12 | themselves to additional_user_agent and have their version reflected in the 13 | user agent string. 14 | deprecations: 15 | - We suggest you fill the name and version for the application and client 16 | instead of specifying a custom ``user_agent``. This will then generate a 17 | standard user agent string. 18 | -------------------------------------------------------------------------------- /releasenotes/notes/version-between-b4b0bcf4cecfb9e4.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Exposed ``keystoneauth1.discover.version_between`` as a public function 5 | that can be used to determine if a given version is within a range. 6 | -------------------------------------------------------------------------------- /releasenotes/source/2023.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/2023.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2023.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2023.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2025.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2025.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2025.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/_static/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/releasenotes/source/_static/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/_templates/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/keystoneauth/13ab55fdfdb770dd11de05ed068b9c2dfc319a97/releasenotes/source/_templates/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/conf.py: -------------------------------------------------------------------------------- 1 | # keystoneauth Release Notes documentation build configuration file 2 | 3 | # -- General configuration ------------------------------------------------ 4 | 5 | # Add any Sphinx extension module names here, as strings. They can be 6 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 7 | # ones. 8 | extensions = ['openstackdocstheme', 'reno.sphinxext'] 9 | 10 | # Add any paths that contain templates here, relative to this directory. 11 | templates_path = ['_templates'] 12 | 13 | # The suffix of source filenames. 14 | source_suffix = '.rst' 15 | 16 | # The master toctree document. 17 | master_doc = 'index' 18 | 19 | # General information about the project. 20 | project = 'keystoneauth Release Notes' 21 | copyright = '2015-, Keystone Developers' 22 | 23 | # Release notes are version independent. 24 | 25 | # The short X.Y version. 26 | 27 | # The full version, including alpha/beta/rc tags. 28 | release = '' 29 | # The short X.Y version. 30 | version = '' 31 | 32 | # List of patterns, relative to source directory, that match files and 33 | # directories to ignore when looking for source files. 34 | exclude_patterns = [] 35 | 36 | # The name of the Pygments (syntax highlighting) style to use. 37 | pygments_style = 'native' 38 | 39 | 40 | # -- Options for HTML output ---------------------------------------------- 41 | 42 | # The theme to use for HTML and HTML Help pages. See the documentation for 43 | # a list of builtin themes. 44 | html_theme = 'openstackdocs' 45 | 46 | # Add any paths that contain custom static files (such as style sheets) here, 47 | # relative to this directory. They are copied after the builtin static files, 48 | # so a file named "default.css" will overwrite the builtin "default.css". 49 | html_static_path = ['_static'] 50 | 51 | 52 | # -- Options for LaTeX output --------------------------------------------- 53 | 54 | # Grouping the document tree into LaTeX files. List of tuples 55 | # (source start file, target name, title, 56 | # author, documentclass [howto, manual, or own class]). 57 | latex_documents = [ 58 | ( 59 | 'index', 60 | 'keystoneauthReleaseNotes.tex', 61 | 'keystoneauth Release Notes Documentation', 62 | 'Keystone Developers', 63 | 'manual', 64 | ) 65 | ] 66 | 67 | 68 | # -- Options for Internationalization output ------------------------------ 69 | locale_dirs = ['locale/'] 70 | 71 | 72 | # -- Options for openstackdocstheme ------------------------------------------- 73 | openstackdocs_repo_name = 'openstack/keystoneauth' 74 | openstackdocs_auto_name = False 75 | openstackdocs_bug_project = 'keystoneauth' 76 | openstackdocs_bug_tag = 'doc' 77 | -------------------------------------------------------------------------------- /releasenotes/source/index.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | keystoneauth Release Notes 3 | ============================ 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | 8 | unreleased 9 | 2025.1 10 | 2024.2 11 | 2024.1 12 | 2023.2 13 | 2023.1 14 | zed 15 | yoga 16 | xena 17 | wallaby 18 | victoria 19 | ussuri 20 | train 21 | stein 22 | rocky 23 | queens 24 | pike 25 | ocata 26 | newton 27 | mitaka 28 | -------------------------------------------------------------------------------- /releasenotes/source/mitaka.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Mitaka Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/mitaka 7 | -------------------------------------------------------------------------------- /releasenotes/source/newton.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | Newton Series Release Notes 3 | ============================= 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/newton 7 | -------------------------------------------------------------------------------- /releasenotes/source/ocata.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Ocata Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/ocata 7 | -------------------------------------------------------------------------------- /releasenotes/source/pike.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Pike Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/pike 7 | -------------------------------------------------------------------------------- /releasenotes/source/queens.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Queens Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/queens 7 | -------------------------------------------------------------------------------- /releasenotes/source/rocky.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Rocky Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/rocky 7 | -------------------------------------------------------------------------------- /releasenotes/source/stein.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Stein Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/stein 7 | -------------------------------------------------------------------------------- /releasenotes/source/train.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Train Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/train 7 | -------------------------------------------------------------------------------- /releasenotes/source/unreleased.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | Current Series Release Notes 3 | ============================== 4 | 5 | .. release-notes:: 6 | -------------------------------------------------------------------------------- /releasenotes/source/ussuri.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Ussuri Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/ussuri 7 | -------------------------------------------------------------------------------- /releasenotes/source/victoria.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | Victoria Series Release Notes 3 | ============================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/victoria 7 | -------------------------------------------------------------------------------- /releasenotes/source/wallaby.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Wallaby Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/wallaby 7 | -------------------------------------------------------------------------------- /releasenotes/source/xena.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Xena Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/xena 7 | -------------------------------------------------------------------------------- /releasenotes/source/yoga.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Yoga Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/yoga 7 | -------------------------------------------------------------------------------- /releasenotes/source/zed.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Zed Series Release Notes 3 | ======================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/zed 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Requirements lower bounds listed here are our best effort to keep them up to 2 | # date but we do not test them so no guarantee of having them all correct. If 3 | # you find any incorrect lower bounds, let us know or propose a fix. 4 | 5 | # All additions to this file must have significant justification. 6 | 7 | # NOTE(morgan) At no time may any oslo library be added to the keystoneauth 8 | # requirements. The requirements for keystoneauth are very tightly controlled 9 | # to ensure we are not pulling in a ton of transient dependencies. This is 10 | # important from the standpoint of ensuring keystoneauth can be used outside 11 | # of openstack-specific projects (allowing interaction with openstack APIs) 12 | # where oslo and associated transient dependencies are not desired. 13 | 14 | pbr>=2.0.0 # Apache-2.0 15 | iso8601>=2.0.0 # MIT 16 | requests>=2.14.2 # Apache-2.0 17 | stevedore>=1.20.0 # Apache-2.0 18 | os-service-types>=1.2.0 # Apache-2.0 19 | typing-extensions>=4.12 # PSF 20 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = keystoneauth1 3 | summary = Authentication Library for OpenStack Identity 4 | description_file = 5 | README.rst 6 | long_description_content_type = text/x-rst 7 | author = OpenStack 8 | author_email = openstack-discuss@lists.openstack.org 9 | home_page = https://docs.openstack.org/keystoneauth/latest/ 10 | project_urls = 11 | Documentation = https://docs.openstack.org/keystoneauth/latest/ 12 | Source = https://opendev.org/openstack/keystoneauth 13 | Bugs = https://bugs.launchpad.net/keystoneauth 14 | Release Notes = https://docs.openstack.org/releasenotes/keystoneauth/ 15 | python_requires = >=3.10 16 | classifier = 17 | Environment :: OpenStack 18 | Intended Audience :: Information Technology 19 | Intended Audience :: System Administrators 20 | License :: OSI Approved :: Apache Software License 21 | Operating System :: POSIX :: Linux 22 | Programming Language :: Python 23 | Programming Language :: Python :: Implementation :: CPython 24 | Programming Language :: Python :: 3 :: Only 25 | Programming Language :: Python :: 3 26 | Programming Language :: Python :: 3.10 27 | Programming Language :: Python :: 3.11 28 | Programming Language :: Python :: 3.12 29 | Programming Language :: Python :: 3.13 30 | 31 | [files] 32 | packages = 33 | keystoneauth1 34 | 35 | [extras] 36 | kerberos = 37 | requests-kerberos>=0.8.0 # ISC 38 | saml2 = 39 | lxml>=4.2.0 # BSD 40 | oauth1 = 41 | oauthlib>=0.6.2 # BSD 42 | betamax = 43 | betamax>=0.7.0 # Apache-2.0 44 | fixtures>=3.0.0 # Apache-2.0/BSD 45 | PyYAML>=3.13 # MIT 46 | 47 | [entry_points] 48 | keystoneauth1.plugin = 49 | none = keystoneauth1.loading._plugins.noauth:NoAuth 50 | http_basic = keystoneauth1.loading._plugins.http_basic:HTTPBasicAuth 51 | password = keystoneauth1.loading._plugins.identity.generic:Password 52 | token = keystoneauth1.loading._plugins.identity.generic:Token 53 | admin_token = keystoneauth1.loading._plugins.admin_token:AdminToken 54 | v2password = keystoneauth1.loading._plugins.identity.v2:Password 55 | v2token = keystoneauth1.loading._plugins.identity.v2:Token 56 | v3password = keystoneauth1.loading._plugins.identity.v3:Password 57 | v3token = keystoneauth1.loading._plugins.identity.v3:Token 58 | v3oidcclientcredentials = keystoneauth1.loading._plugins.identity.v3:OpenIDConnectClientCredentials 59 | v3oidcpassword = keystoneauth1.loading._plugins.identity.v3:OpenIDConnectPassword 60 | v3oidcdeviceauthz = keystoneauth1.loading._plugins.identity.v3:OpenIDConnectDeviceAuthorization 61 | v3oidcauthcode = keystoneauth1.loading._plugins.identity.v3:OpenIDConnectAuthorizationCode 62 | v3oidcaccesstoken = keystoneauth1.loading._plugins.identity.v3:OpenIDConnectAccessToken 63 | v3oauth1 = keystoneauth1.extras.oauth1._loading:V3OAuth1 64 | v3kerberos = keystoneauth1.extras.kerberos._loading:Kerberos 65 | v3totp = keystoneauth1.loading._plugins.identity.v3:TOTP 66 | v3fedkerb = keystoneauth1.extras.kerberos._loading:MappedKerberos 67 | v3tokenlessauth = keystoneauth1.loading._plugins.identity.v3:TokenlessAuth 68 | v3adfspassword = keystoneauth1.extras._saml2._loading:ADFSPassword 69 | v3samlpassword = keystoneauth1.extras._saml2._loading:Saml2Password 70 | v3applicationcredential = keystoneauth1.loading._plugins.identity.v3:ApplicationCredential 71 | v3multifactor = keystoneauth1.loading._plugins.identity.v3:MultiFactor 72 | v3oauth2clientcredential = keystoneauth1.loading._plugins.identity.v3:OAuth2ClientCredential 73 | v3oauth2mtlsclientcredential = keystoneauth1.loading._plugins.identity.v3:OAuth2mTlsClientCredential 74 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import setuptools 17 | 18 | setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True) 19 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | hacking~=6.1.0 # Apache-2.0 2 | flake8-docstrings~=1.7.0 # MIT 3 | flake8-import-order~=0.18.2 #LGPLv3 4 | bandit~=1.7.6 # Apache-2.0 5 | 6 | coverage>=4.0 # Apache-2.0 7 | fixtures>=3.0.0 # Apache-2.0/BSD 8 | oslo.config>=5.2.0 # Apache-2.0 9 | oslo.utils>=3.33.0 # Apache-2.0 10 | oslotest>=3.2.0 # Apache-2.0 11 | betamax>=0.7.0 # Apache-2.0 12 | requests-mock>=1.2.0 # Apache-2.0 13 | stestr>=1.0.0 # Apache-2.0 14 | testresources>=2.0.0 # Apache-2.0/BSD 15 | testtools>=2.2.0 # MIT 16 | PyYAML>=3.12 # MIT 17 | requests-kerberos>=0.8.0 # ISC 18 | lxml>=4.2.0 # BSD 19 | oauthlib>=0.6.2 # BSD 20 | --------------------------------------------------------------------------------