diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 2f17ab1b..00000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = keystoneclient -omit = keystoneclient/tests/* - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6b6f10de..00000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -.coverage -.testrepository -subunit.log -.venv -*,cover -cover -*.pyc -.idea -*.sw? -*.egg -*~ -.tox -AUTHORS -ChangeLog -build -dist -python_keystoneclient.egg-info -keystoneclient/versioninfo -doc/source/api -# Development environment files -.project -.pydevproject -# Temporary files created during test, but not removed -examples/pki/certs/tmp* -# Files created by releasenotes build -releasenotes/build diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 56224f5d..00000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/python-keystoneclient.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index c804401b..00000000 --- a/.mailmap +++ /dev/null @@ -1,6 +0,0 @@ -# Format is: -# -# - - - diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 3d3e1e6e..00000000 --- a/.testr.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -test_command=${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystoneclient/tests/unit} $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 604d3ac7..00000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,18 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps documented at: - - https://docs.openstack.org/infra/manual/developers.html - -If you already have a good understanding of how the system works -and your OpenStack accounts are set up, you can skip to the -development workflow section of this documentation to learn how -changes to OpenStack should be submitted for review via the -Gerrit tool: - - https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/python-keystoneclient diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 6ea94ff6..00000000 --- a/HACKING.rst +++ /dev/null @@ -1,24 +0,0 @@ -Keystone Style Commandments -=========================== - -- Step 1: Read the OpenStack Style Commandments - https://docs.openstack.org/hacking/latest/ -- Step 2: Read on - -Exceptions ----------- - -When dealing with exceptions from underlying libraries, translate those -exceptions to an instance or subclass of ClientException. - -======= -Testing -======= - -python-keystoneclient uses testtools and testr for its unittest suite -and its test runner. Basic workflow around our use of tox and testr can -be found at https://wiki.openstack.org/testr. If you'd like to learn more -in depth: - - https://testtools.readthedocs.org/ - https://testrepository.readthedocs.org/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 32b66114..00000000 --- a/LICENSE +++ /dev/null @@ -1,209 +0,0 @@ -Copyright (c) 2009 Jacob Kaplan-Moss - initial codebase (< v2.1) -Copyright (c) 2011 Rackspace - OpenStack extensions (>= v2.1) -Copyright (c) 2011 Nebula, Inc - Keystone refactor (>= v2.7) -All rights reserved. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README new file mode 100644 index 00000000..8fcd2b2f --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index 33edffb7..00000000 --- a/README.rst +++ /dev/null @@ -1,64 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: https://governance.openstack.org/badges/python-keystoneclient.svg - :target: https://governance.openstack.org/reference/tags/index.html - -.. Change things from this point on - -Python bindings to the OpenStack Identity API (Keystone) -======================================================== - -.. image:: https://img.shields.io/pypi/v/python-keystoneclient.svg - :target: https://pypi.python.org/pypi/python-keystoneclient/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/python-keystoneclient.svg - :target: https://pypi.python.org/pypi/python-keystoneclient/ - :alt: Downloads - -This is a client for the OpenStack Identity API, implemented by the Keystone -team; it contains a Python API (the ``keystoneclient`` module) for -OpenStack's Identity Service. For command line interface support, use -`OpenStackClient`_. - -* `PyPi`_ - package installation -* `Online Documentation`_ -* `Launchpad project`_ - release management -* `Blueprints`_ - feature specifications -* `Bugs`_ - issue tracking -* `Source`_ -* `Specs`_ -* `How to Contribute`_ - -.. _PyPi: https://pypi.python.org/pypi/python-keystoneclient -.. _Online Documentation: https://docs.openstack.org/python-keystoneclient/latest/ -.. _Launchpad project: https://launchpad.net/python-keystoneclient -.. _Blueprints: https://blueprints.launchpad.net/python-keystoneclient -.. _Bugs: https://bugs.launchpad.net/python-keystoneclient -.. _Source: https://git.openstack.org/cgit/openstack/python-keystoneclient -.. _OpenStackClient: https://pypi.python.org/pypi/python-openstackclient -.. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html -.. _Specs: https://specs.openstack.org/openstack/keystone-specs/ - -.. contents:: Contents: - :local: - -Python API ----------- - -By way of a quick-start:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - >>> auth = v3.Password(auth_url="http://example.com:5000/v3", username="admin", - ... password="password", project_name="admin", - ... user_domain_id="default", project_domain_id="default") - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.projects.list() - [...] - >>> project = keystone.projects.create(name="test", description="My new Project!", domain="default", enabled=True) - >>> project.delete() diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab81..00000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index d1793694..00000000 --- a/bindep.txt +++ /dev/null @@ -1,23 +0,0 @@ -# This is a cross-platform list tracking distribution packages needed by tests; -# see https://docs.openstack.org/infra/bindep/ for additional information. - -gettext -libssl-dev - -dbus-devel [platform:rpm] -dbus-glib-devel [platform:rpm] -libdbus-1-dev [platform:dpkg] -libdbus-glib-1-dev [platform:dpkg] -libffi-dev [platform:dpkg] -libffi-devel [platform:rpm] -libsasl2-dev [platform:dpkg] -libxml2-dev [platform:dpkg] -libxslt1-dev [platform:dpkg] -python-all-dev [platform:dpkg] -python3-all-dev [platform:dpkg] - -cyrus-sasl-devel [platform:rpm] -libxml2-devel [platform:rpm] -python-devel [platform:rpm] -python3-devel [platform:fedora] -python34-devel [platform:centos] diff --git a/doc/.gitignore b/doc/.gitignore deleted file mode 100644 index 567609b1..00000000 --- a/doc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 430e5a33..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,90 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXSOURCE = source -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SPHINXSOURCE) - -.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-keystoneclient.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-keystoneclient.qhc" - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ - "run these through (pdf)latex." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 56363055..00000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,232 +0,0 @@ -# python-keystoneclient documentation build configuration file, created by -# sphinx-quickstart on Sun Dec 6 14:19:25 2009. -# -# This file is execfile()d with the current directory set to its containing -# dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -from __future__ import unicode_literals - -import os -import sys - -import pbr.version - - -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), - '..', '..'))) - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) - -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.intersphinx', - 'openstackdocstheme', - ] - -todo_include_todos = True - -# Add any paths that contain templates here, relative to this directory. -# templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'python-keystoneclient' -copyright = 'OpenStack Contributors' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -version_info = pbr.version.VersionInfo('python-keystoneclient') -# The short X.Y version. -version = version_info.version_string() -# The full version, including alpha/beta/rc tags. -release = version_info.release_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of documents that shouldn't be included in the build. -#unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['keystoneclient.'] - -# Grouping the document tree for man pages. -# List of tuples 'sourcefile', 'target', 'title', 'Authors name', 'manual' - -#man_pages = [] - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -#html_theme_path = ["."] -#html_theme = '_theme' -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_use_modindex = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'python-keystoneclientdoc' - - -# -- Options for LaTeX output ------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]) -# . -latex_documents = [ - ('index', 'python-keystoneclient.tex', - 'python-keystoneclient Documentation', - 'Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss', - 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_use_modindex = True - -keystoneauth_url = 'https://docs.openstack.org/keystoneauth/latest/' -intersphinx_mapping = { - 'python': ('https://docs.python.org/', None), - 'osloconfig': ('https://docs.openstack.org/oslo.config/latest/', None), - 'keystoneauth1': (keystoneauth_url, None), -} - -# -- Options for openstackdocstheme ------------------------------------------- -repository_name = 'openstack/python-keystoneclient' -bug_project = 'python-keystoneclient' -bug_tag = '' diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 69ed4fe6..00000000 --- a/doc/source/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index bee96306..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,54 +0,0 @@ -Python bindings to the OpenStack Identity API (Keystone) -======================================================== - -This is a client for OpenStack Identity API. There's a Python API for -:doc:`Identity API v3 ` and :doc:`v2 ` (the -:mod:`keystoneclient` modules). - -Contents: - -.. toctree:: - :maxdepth: 1 - - using-api-v3 - using-sessions - using-api-v2 - api/modules - -Related Identity Projects -========================= - -In addition to creating the Python client library, the Keystone team also -provides `Identity Service`_, as well as `WSGI Middleware`_. - -.. _`Identity Service`: https://docs.openstack.org/keystone/latest/ -.. _`WSGI Middleware`: https://docs.openstack.org/keystonemiddleware/latest/ - -Release Notes -============= - -.. toctree:: - :maxdepth: 1 - - history - -Contributing -============ - -Code is hosted `on GitHub`_. Submit bugs to the Keystone project on -`Launchpad`_. Submit code to the ``openstack/python-keystoneclient`` project -using `Gerrit`_. - -.. _on GitHub: https://github.com/openstack/python-keystoneclient -.. _Launchpad: https://launchpad.net/python-keystoneclient -.. _Gerrit: https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Run tests with ``tox``. - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/using-api-v2.rst b/doc/source/using-api-v2.rst deleted file mode 100644 index 1b7c5dea..00000000 --- a/doc/source/using-api-v2.rst +++ /dev/null @@ -1,125 +0,0 @@ -======================= -Using the V2 client API -======================= - -Introduction -============ - -The main concepts in the Identity v2 API are: - - * tenants - * users - * roles - * services - * endpoints - -The V2 client API lets you query and make changes through -managers. For example, to manipulate tenants, you interact with a -``keystoneclient.v2_0.tenants.TenantManager`` object. - -You obtain access to managers via attributes of the -``keystoneclient.v2_0.client.Client`` object. For example, the ``tenants`` -attribute of the ``Client`` class is a tenant manager:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> keystone.tenants.list() # List tenants - -You create a valid ``keystoneclient.v2_0.client.Client`` object by passing -a :class:`~keystoneauth1.session.Session` to the constructor. Authentication -and examples of common tasks are provided below. - -You can generally expect that when the client needs to propagate an exception -it will raise an instance of subclass of -``keystoneclient.exceptions.ClientException`` - -Authenticating -============== - -There are two ways to authenticate against keystone: - * against the admin endpoint with the admin token - * against the public endpoint with a username and password - -If you are an administrator, you can authenticate by connecting to the admin -endpoint and using the admin token (sometimes referred to as the service -token). The token is specified as the ``admin_token`` configuration option in -your keystone.conf config file, which is typically in /etc/keystone:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> token = '012345SECRET99TOKEN012345' - >>> endpoint = 'http://192.168.206.130:35357/v2.0' - >>> auth = v2.Token(auth_url=endpoint, token=token) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - -If you have a username and password, authentication is done against the -public endpoint. You must also specify a tenant that is associated with the -user:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> username='adminUser' - >>> password='secretword' - >>> tenant_name='openstackDemo' - >>> auth_url='http://192.168.206.130:5000/v2.0' - >>> auth = v2.Password(username=username, password=password, - ... tenant_name=tenant_name, auth_url=auth_url) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - -Creating tenants -================ - -This example will create a tenant named *openstackDemo*:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> keystone.tenants.create(tenant_name="openstackDemo", - ... description="Default Tenant", enabled=True) - - -Creating users -============== - -This example will create a user named *adminUser* with a password *secretword* -in the openstackDemo tenant. We first need to retrieve the tenant:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> tenants = keystone.tenants.list() - >>> my_tenant = [x for x in tenants if x.name=='openstackDemo'][0] - >>> my_user = keystone.users.create(name="adminUser", - ... password="secretword", - ... tenant_id=my_tenant.id) - -Creating roles and adding users -=============================== - -This example will create an admin role and add the *my_user* user to that -role, but only for the *my_tenant* tenant: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> role = keystone.roles.create('admin') - >>> my_tenant = ... - >>> my_user = ... - >>> keystone.roles.add_user_role(my_user, role, my_tenant) - -Creating services and endpoints -=============================== - -This example will create the service and corresponding endpoint for the -Compute service:: - - >>> from keystoneclient.v2_0 import client - >>> keystone = client.Client(...) - >>> service = keystone.services.create(name="nova", service_type="compute", - ... description="Nova Compute Service") - >>> keystone.endpoints.create( - ... region="RegionOne", service_id=service.id, - ... publicurl="http://192.168.206.130:8774/v2/%(tenant_id)s", - ... adminurl="http://192.168.206.130:8774/v2/%(tenant_id)s", - ... internalurl="http://192.168.206.130:8774/v2/%(tenant_id)s") diff --git a/doc/source/using-api-v3.rst b/doc/source/using-api-v3.rst deleted file mode 100644 index f0c82c5f..00000000 --- a/doc/source/using-api-v3.rst +++ /dev/null @@ -1,140 +0,0 @@ -======================= -Using the V3 Client API -======================= - -Introduction -============ - -The main concepts in the Identity v3 API are: - - * :py:mod:`~keystoneclient.v3.credentials` - * :py:mod:`~keystoneclient.v3.domain_configs` - * :py:mod:`~keystoneclient.v3.domains` - * :py:mod:`~keystoneclient.v3.endpoints` - * :py:mod:`~keystoneclient.v3.groups` - * :py:mod:`~keystoneclient.v3.policies` - * :py:mod:`~keystoneclient.v3.projects` - * :py:mod:`~keystoneclient.v3.regions` - * :py:mod:`~keystoneclient.v3.role_assignments` - * :py:mod:`~keystoneclient.v3.roles` - * :py:mod:`~keystoneclient.v3.services` - * :py:mod:`~keystoneclient.v3.tokens` - * :py:mod:`~keystoneclient.v3.users` - -The :py:mod:`keystoneclient.v3.client` API lets you query and make changes -through ``managers``. For example, to manipulate a project (formerly -called tenant), you interact with a -:py:class:`keystoneclient.v3.projects.ProjectManager` object. - -You obtain access to managers through attributes of a -:py:class:`keystoneclient.v3.client.Client` object. For example, the -``projects`` attribute of a ``Client`` object is a projects manager:: - - >>> from keystoneclient.v3 import client - >>> keystone = client.Client(...) - >>> keystone.projects.list() # List projects - -While it is possible to instantiate a -:py:class:`keystoneclient.v3.client.Client` object (as done above for -clarity), the recommended approach is to use the discovery mechanism -provided by the :py:class:`keystoneclient.client.Client` class. The -appropriate class will be instantiated depending on the API versions -available:: - - >>> from keystoneclient import client - >>> keystone = - ... client.Client(auth_url='http://localhost:5000', ...) - >>> type(keystone) - - -One can force the use of a specific version of the API, either by -using the ``version`` keyword argument:: - - >>> from keystoneclient import client - >>> keystone = client.Client(auth_url='http://localhost:5000', - version=(2,), ...) - >>> type(keystone) - - >>> keystone = client.Client(auth_url='http://localhost:5000', - version=(3,), ...) - >>> type(keystone) - - -Or by specifying directly the specific API version authentication URL -as the auth_url keyword argument:: - - >>> from keystoneclient import client - >>> keystone = - ... client.Client(auth_url='http://localhost:5000/v2.0', ...) - >>> type(keystone) - - >>> keystone = - ... client.Client(auth_url='http://localhost:5000/v3', ...) - >>> type(keystone) - - -Upon successful authentication, a :py:class:`keystoneclient.v3.client.Client` -object is returned (when using the Identity v3 API). Authentication and -examples of common tasks are provided below. - -You can generally expect that when the client needs to propagate an -exception it will raise an instance of subclass of -:class:`keystoneclient.exceptions.ClientException`. - -Authenticating Using Sessions -============================= - -Instantiate a :py:class:`keystoneclient.v3.client.Client` using a -:py:class:`~keystoneauth1.session.Session` to provide the authentication -plugin, SSL/TLS certificates, and other data:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - >>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v3', - ... user_id='myuserid', - ... password='mypassword', - ... project_id='myprojectid') - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - -For more information on Sessions refer to: `Using Sessions`_. - -.. _`Using Sessions`: using-sessions.html - -Non-Session Authentication (deprecated) -======================================= - -The *deprecated* way to authenticate is to pass the username, the user's domain -name (which will default to 'Default' if it is not specified), and a -password:: - - >>> from keystoneclient import client - >>> auth_url = 'http://localhost:5000' - >>> username = 'adminUser' - >>> user_domain_name = 'Default' - >>> password = 'secreetword' - >>> keystone = client.Client(auth_url=auth_url, version=(3,), - ... username=username, password=password, - ... user_domain_name=user_domain_name) - -A :py:class:`~keystoneauth1.session.Session` should be passed to the Client -instead. Using a Session you're not limited to authentication using a username -and password but can take advantage of other more secure authentication -methods. - -You may optionally specify a domain or project (along with its project -domain name), to obtain a scoped token:: - - >>> from keystoneclient import client - >>> auth_url = 'http://localhost:5000' - >>> username = 'adminUser' - >>> user_domain_name = 'Default' - >>> project_name = 'demo' - >>> project_domain_name = 'Default' - >>> password = 'secreetword' - >>> keystone = client.Client(auth_url=auth_url, version=(3,), - ... username=username, password=password, - ... user_domain_name=user_domain_name, - ... project_name=project_name, - ... project_domain_name=project_domain_name) diff --git a/doc/source/using-sessions.rst b/doc/source/using-sessions.rst deleted file mode 100644 index a5a5a58d..00000000 --- a/doc/source/using-sessions.rst +++ /dev/null @@ -1,200 +0,0 @@ -============== -Using Sessions -============== - -Introduction -============ - -The :py:class:`keystoneauth1.session.Session` class was introduced into -keystoneclient as an attempt to bring a unified interface to the various -OpenStack clients that share common authentication and request parameters -between a variety of services. - -The model for using a Session and auth plugin as well as the general terms used -have been heavily inspired by the `requests `_ -library. However neither the Session class nor any of the authentication -plugins rely directly on those concepts from the requests library so you should -not expect a direct translation. - -Features --------- - -- Common client authentication - - Authentication is handled by one of a variety of authentication plugins and - then this authentication information is shared between all the services that - use the same Session object. - -- Security maintenance - - Security code is maintained in a single place and reused between all - clients such that in the event of problems it can be fixed in a single - location. - -- Standard discovery mechanisms - - Clients are not expected to have any knowledge of an identity token or any - other form of identification credential. Service and endpoint discovery are - handled by the Session and plugins. - - -Sessions for Users -================== - -The Session object is the contact point to your OpenStack cloud services. It -stores the authentication credentials and connection information required to -communicate with OpenStack such that it can be reused to communicate with many -services. When creating services this Session object is passed to the client -so that it may use this information. - -A Session will authenticate on demand. When a request that requires -authentication passes through the Session the authentication plugin will be -asked for a valid token. If a valid token is available it will be used -otherwise the authentication plugin may attempt to contact the authentication -service and fetch a new one. - -An example from keystoneclient:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - - >>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v3', - ... username='myuser', - ... password='mypassword', - ... project_id='proj', - ... user_domain_id='domain') - >>> sess = session.Session(auth=auth, - ... verify='/path/to/ca.cert') - >>> ks = client.Client(session=sess) - >>> users = ks.users.list() - -As clients adopt this means of operating they will be created in a similar -fashion by passing the Session object to the client's constructor. - - -Migrating keystoneclient to use a Session ------------------------------------------ - -By using a session with a keystoneclient Client we presume that you have opted -in to new behavior defined by the session. For example authentication is now -on-demand rather than on creation. To allow this change in behavior there are -a number of functions that have changed behavior or are no longer available. - -For example the -:py:meth:`keystoneclient.httpclient.HTTPClient.authenticate` method used -to be able to always re-authenticate the current client and fetch a new token. -As this is now controlled by the Session and not the client this has changed, -however the function will still exist to provide compatibility with older -clients. - -Likewise certain parameters such as ``user_id`` and ``auth_token`` that used to -be available on the client object post authentication will remain -uninitialized. - -When converting an application to use a session object with keystoneclient you -should be aware of the possibility of changes to authentication and -authentication parameters and make sure to test your code thoroughly. It should -have no impact on the typical CRUD interaction with the client. - - -Sharing Authentication Plugins ------------------------------- - -A session can only contain one authentication plugin however there is nothing -that specifically binds the authentication plugin to that session, a new -Session can be created that reuses the existing authentication plugin:: - - >>> new_sess = session.Session(auth=sess.auth, - verify='/path/to/different-cas.cert') - -In this case we cannot know which session object will be used when the plugin -performs the authentication call so the command must be able to succeed with -either. - -Authentication plugins can also be provided on a per-request basis. This will -be beneficial in a situation where a single session is juggling multiple -authentication credentials:: - - >>> sess.get('https://my.keystone.com:5000/v3', - auth=my_auth_plugin) - -If an auth plugin is provided via parameter then it will override any auth -plugin on the session. - -Sessions for Client Developers -============================== - -Sessions are intended to take away much of the hassle of dealing with -authentication data and token formats. Clients should be able to specify filter -parameters for selecting the endpoint and have the parsing of the catalog -managed for them. - -Authentication --------------- - -When making a request with a session object you can simply pass the keyword -parameter ``authenticated`` to indicate whether the argument should contain a -token, by default a token is included if an authentication plugin is available:: - - >>> # In keystone this route is unprotected by default - >>> resp = sess.get('https://my.keystone.com:5000/v3', - authenticated=False) - - -Service Discovery ------------------ - -In OpenStack the URLs of available services are distributed to the user as a -part of the token they receive called the Service Catalog. Clients are expected -to use the URLs from the Service Catalog rather than have them provided. - -In general a client does not need to know the full URL for the server that they -are communicating with, simply that it should send a request to a path -belonging to the correct service. - -This is controlled by the ``endpoint_filter`` parameter to a request which -contains all the information an authentication plugin requires to determine the -correct URL to which to send a request. When using this mode only the path for -the request needs to be specified:: - - >>> resp = session.get('/v3/users', - endpoint_filter={'service_type': 'identity', - 'interface': 'public', - 'region_name': 'myregion'}) - -``endpoint_filter`` accepts a number of arguments with which it can determine -an endpoint url: - -- ``service_type``: the type of service. For example ``identity``, ``compute``, - ``volume`` or many other predefined identifiers. - -- ``interface``: the network exposure the interface has. This will be one of: - - - ``public``: An endpoint that is available to the wider internet or network. - - ``internal``: An endpoint that is only accessible within the private network. - - ``admin``: An endpoint to be used for administrative tasks. - -- ``region_name``: the name of the region where the endpoint resides. - -The endpoint filter is a simple key-value filter and can be provided with any -number of arguments. It is then up to the auth plugin to correctly use the -parameters it understands. - -The session object determines the URL matching the filter and append to it the -provided path and so create a valid request. If multiple URL matches are found -then any one may be chosen. - -While authentication plugins will endeavour to maintain a consistent set of -arguments for an ``endpoint_filter`` the concept of an authentication plugin is -purposefully generic and a specific mechanism may not know how to interpret -certain arguments and ignore them. For example the -:py:class:`keystoneauth1.identity.generic.token.Token` plugin (which is used -when you want to always use a specific endpoint and token combination) will -always return the same endpoint regardless of the parameters to -``endpoint_filter`` or a custom OpenStack authentication mechanism may not have -the concept of multiple ``interface`` options and choose to ignore that -parameter. - -There is some expectation on the user that they understand the limitations of -the authentication system they are using. diff --git a/examples/pki/certs/cacert.pem b/examples/pki/certs/cacert.pem deleted file mode 100644 index 952bdaea..00000000 --- a/examples/pki/certs/cacert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID1jCCAr6gAwIBAgIJAJOtRP2+wrM/MA0GCSqGSIb3DQEBBQUAMIGeMQowCAYD -VQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55 -dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMG -CSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2Vs -ZiBTaWduZWQwIBcNMTMwOTEzMTYyNTQyWhgPMjA3MjAzMDcxNjI1NDJaMIGeMQow -CAYDVQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1 -bm55dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTEl -MCMGCSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxML -U2VsZiBTaWduZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCl8906 -EaRpibQFcCBWfxzLi5x/XpZ9iL6UX92NrSJxcDbaGws7s+GtjgDy8UOEonesRWTe -qQEZtHpC3/UHHOnsA8F6ha/pq9LioqT7RehCnZCLBJwh5Ct+lclpWs15SkjJD2LT -Dkjox0eA9nOBx+XDlWyU/GAyqx5Wsvg/Kxr0iod9/4IcJdnSdUjq4v0Cxg/zNk08 -XPJX+F0bUDhgdUf7JrAmmS5LA8wphRnbIgtVsf6VN9HrbqtHAJDxh8gEfuwdhEW1 -df1fBtZ+6WMIF3IRSbIsZELFB6sqcyRj7HhMoWMkdEyPb2f8mq61MzTgE6lJGIyT -RvEoFie7qtGADIofAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEFBQADggEBAJRMdEwAdN+crqI9dBLYlbBbnQ8xr9mk+REMdz9+SKhDCNdVisWU -iLEZvK/aozrsRsDi81JjS4Tz0wXo8zsPPoDnXgDYEicNPTKifbPKgHdDIGFOwBKn -y2cF6fHEn8n3KIBrDCNY6rHcYGZ7lbq/8eF0GoYQboPiuYesvVpynPmIK5/Mmire -EuuZALAe1IFqqFt+l6tiJU2JWUFjLkFARMOD14qFZm+SInl64toi08j6gdou+NMW -7GEMbVHwNTafM/TgFN5j0yP9SAnYubckLSyH6hwR+rM8dztP5769joxQfnc9O/Bn -TBD9KFpeQv6VJWLAxiIKcQCRTTDJLZZ0MQI= ------END CERTIFICATE----- diff --git a/examples/pki/certs/middleware.pem b/examples/pki/certs/middleware.pem deleted file mode 100644 index 7d593efd..00000000 --- a/examples/pki/certs/middleware.pem +++ /dev/null @@ -1,50 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpjCCAo4CARAwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK -EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr -ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x -MzA5MTMxNjI1NDNaGA8yMDcyMDMwNzE2MjU0M1owgZAxCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh -Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv -cGVuc3RhY2sub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDL06AaJROwHPgJ9tcySSBepzJ81jYars2sMvLjyuvd -iIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rpv8dGDIDsxZQVjT/4SLaQUOeDM+9b -fkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLYWso0SJD0vAi1gmGDlSM/mmhhHTpC -DGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1ZrslPC5lFvlHD7KBBf6IU2A8Xh/dUa3 -p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYRR45pPCVkk6vFsy6P0JwwpnkszB+L -cK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4YEPirGGrAgMBAAEwDQYJKoZIhvcN -AQEFBQADggEBAAjU7YomUx/U56p1KWHvr1B7oczHF8fPHYbuk5c/N81WOJeSRy+P -5ZGZ2UPjvqqXByv+78YWMKGY1BZ/2doeWuydr0sdSxEwmIUBYxFpujuYY+0AjS/n -mMr1ZijK7TJssteKM7/MClzghUhPweDZrAg3ff1hbhK5QSy+9UPxUqLH44tfYSVC -/BzM6se0p5ToM0bwdsa8TofaBRE1L1IW/Hg4VIGOoKs0R0uLm7+Oot2me2cEuZ6h -Wls6MED8ND1Nz8EAKwndkeDu2iMM+qx/YFp6K8BQ5E5nXd2rbUZUlQMp1WbUlZ87 -KvC98aT0UYIq6uo1Lx/dQvJs7faAkYd4lmE= ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL06AaJROwHPgJ -9tcySSBepzJ81jYars2sMvLjyuvdiIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rp -v8dGDIDsxZQVjT/4SLaQUOeDM+9bfkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLY -Wso0SJD0vAi1gmGDlSM/mmhhHTpCDGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1Zrs -lPC5lFvlHD7KBBf6IU2A8Xh/dUa3p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYR -R45pPCVkk6vFsy6P0JwwpnkszB+LcK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4 -YEPirGGrAgMBAAECggEATwvbY0hNwlb5uqOIAXBqpUqiQdexU9fG26lGmSDxKBDv -9o5frcRgBDrMWwvDCgY+HT4CAvB9kJx4/qnpVjkzJp/ZNiJ5VIiehIlbv348rXbh -xkk+bz5dDATCFOXuu1fwL2FhyM5anwhMAav0DyK1VLQ3jGzr9GO6L8hqAn+bQFFu -6ngiODwfhBMl5aRoL9UOBEhccK07znrH0JGRz+3+5Cdz59Xw91Bv210LhNNDL58+ -0JD0N+YztVOQd2bgwo0bQbOEijzmYq+0mjoqAnJh1/++y7PlIPs0AnPgqSnFPx9+ -6FsQEVRgk5Uq3kvPLaP4nT2y6MDZSp+ujYldvJhyQQKBgQDuX2pZIJMZ4aFnkG+K -TmJ5wsLa/u9an0TmvAL9RLtBpVpQNKD8cQ+y8PUZavXDbAIt5NWqZVnTbCR79Dnd -mZKblwcHhtsyA5f89el5KcxY2BREWdHdTnJpNd7XRlUECmzvX1zGj77lA982PhII -yflRBRV3vqLkgC8vfoYgRyRElwKBgQDa5jnLdx/RahfYMOgn1HE5o4hMzLR4Y0Dd -+gELshcUbPqouoP5zOb8WOagVJIgZVOSN+/VqbilVYrqRiNTn2rnoxs+HHRdaJNN -3eXllD4J2HfC2BIj1xSpIdyh2XewAJqw9IToHNB29QUhxOtgwseHciPG6JaKH2ik -kqGKH/EKDQKBgFFAftygiOPCkCTgC9UmANUmOQsy6N2H+pF3tsEj43xt44oBVnqW -A1boYXNnjRwuvdNs9BPf9i1l6E3EItFRXrLgWQoMwryakv0ryYh+YeRKyyW9RBbe -fYs1TJ8unx4Ae79gTxxztQsVNcmkgLs0NWKTjAzEE3w14V+cDhYEie1DAoGBAJdI -V5cLrBzBstsB6eBlDR9lqrRRIUS2a8U9m+1mVlcSfiWQSdehSd4K3tDdwePLw3ch -W4qR8n+pYAlLEe0gFvUhn5lMdwt7U5qUCeehjUKmrRYm2FqWsbu2IFJnBjXIJSC4 -zQXRrC0aZ0KQYpAL7XPpaVp1slyhGmPqxuO78Y0dAoGBAMHo3EIMwu9rfuGwFodr -GFsOZhfJqgo5GDNxxf89Q9WWpMDTCdX+wdBTrN/wsMbBuwIDHrUuRnk6D5CWRjSk -/ikCgHN3kOtrbL8zzqRomGAIIWKYGFEIGe1GHVGo5r//HXHdPxFXygvruQ/xbOA4 -RGvmDiji8vVDq7Shho8I6KuT ------END PRIVATE KEY----- diff --git a/examples/pki/certs/signing_cert.pem b/examples/pki/certs/signing_cert.pem deleted file mode 100644 index 63ab2478..00000000 --- a/examples/pki/certs/signing_cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpTCCAo0CAREwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK -EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr -ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x -MzA5MTMxNjI1NDNaGA8yMDcyMDMwNzE2MjU0M1owgY8xCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh -Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv -cGVuc3RhY2sub3JnMREwDwYDVQQDEwhLZXlzdG9uZTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAMz5WsgsuX3rZUdLwQpZXN2Ro7LQ6jEZnreBqMztVObw -BuC1WdiJsg6dVlC7PVdt+0gY1c8WFg1TKmsucxesQSyfGAPg+9T/hsRMb6y12uJx -fp3Wgqqw0U1HsXvMiaJH87MaGnt043BxzF+R9fhAcDk6Cyj5cx9J0LvZJEOzN4J4 -ZRyO6j/DZZItb3lK5W9xkuoT+mTdDZOQJnXyG818uiWfjdCkLjr1ruytRcBOo4na -Y828voT/A7I95+YCgKgbjiUWhHeTaNmMEQiGy0nGYfteC+oSsHOlxZ3b12azzHPk -83Bh2ez0Ih9vcZoe9DqvlFOXfv9q8OsYc5Yo6gPTXEsCAwEAATANBgkqhkiG9w0B -AQUFAAOCAQEAmaYE98kOQWu6DV84ZcZP/OdT8eeu3vdB247nRj+6+GYItN/Gzqt4 -HVvz7c+FVTolCcAQQ+z3XGswI9fIJ78Hb0p9CgnLprc3L7Xtk60Im59Xlf3tcurn -r/ZnSDcjRBXKiEDrSM0VrhAnc0GoSeb6aDWopec+1hWOWfBVAg9R8yJgU9sUgO3O -0gimGyrw8eubmNhckSQLJTunUTsrkcBjuSg63wAD9OqCiX6c2eoQr+0YBp2eV2/n -aOiJXWNLbeueMKSYiJNyyvM/dlON7/56cdwDTzKzgD34TImouM5VKipUwCX1ovLu -ITLzALzpqFFzc8ugV9pMgUKtDbZoPp9EEA== ------END CERTIFICATE----- diff --git a/examples/pki/certs/ssl_cert.pem b/examples/pki/certs/ssl_cert.pem deleted file mode 100644 index cdd2e4c0..00000000 --- a/examples/pki/certs/ssl_cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpjCCAo4CARAwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK -EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr -ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x -MzA5MTMxNjI1NDNaGA8yMDcyMDMwNzE2MjU0M1owgZAxCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh -Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv -cGVuc3RhY2sub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDL06AaJROwHPgJ9tcySSBepzJ81jYars2sMvLjyuvd -iIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rpv8dGDIDsxZQVjT/4SLaQUOeDM+9b -fkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLYWso0SJD0vAi1gmGDlSM/mmhhHTpC -DGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1ZrslPC5lFvlHD7KBBf6IU2A8Xh/dUa3 -p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYRR45pPCVkk6vFsy6P0JwwpnkszB+L -cK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4YEPirGGrAgMBAAEwDQYJKoZIhvcN -AQEFBQADggEBAAjU7YomUx/U56p1KWHvr1B7oczHF8fPHYbuk5c/N81WOJeSRy+P -5ZGZ2UPjvqqXByv+78YWMKGY1BZ/2doeWuydr0sdSxEwmIUBYxFpujuYY+0AjS/n -mMr1ZijK7TJssteKM7/MClzghUhPweDZrAg3ff1hbhK5QSy+9UPxUqLH44tfYSVC -/BzM6se0p5ToM0bwdsa8TofaBRE1L1IW/Hg4VIGOoKs0R0uLm7+Oot2me2cEuZ6h -Wls6MED8ND1Nz8EAKwndkeDu2iMM+qx/YFp6K8BQ5E5nXd2rbUZUlQMp1WbUlZ87 -KvC98aT0UYIq6uo1Lx/dQvJs7faAkYd4lmE= ------END CERTIFICATE----- diff --git a/examples/pki/cms/auth_token_revoked.json b/examples/pki/cms/auth_token_revoked.json deleted file mode 100644 index eab40a0b..00000000 --- a/examples/pki/cms/auth_token_revoked.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "access": { - "token": { - "expires": "2038-01-18T21:14:07Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "placeholder", - "tenant": { - "id": "tenant_id1", - "enabled": true, - "description": null, - "name": "tenant_name1" - } - }, - "serviceCatalog": [ - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne", - "internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a" - } - ], - "type": "volume", - "name": "volume" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:9292/v1", - "region": "regionOne", - "internalURL": "http://127.0.0.1:9292/v1", - "publicURL": "http://127.0.0.1:9292/v1" - } - ], - "type": "image", - "name": "glance" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne", - "internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a" - } - ], - "type": "compute", - "name": "nova" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:35357/v2.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:35357/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - } - ], - "type": "identity", - "name": "keystone" - } - ], - "user": { - "username": "revoked_username1", - "roles_links": [ - "role1", - "role2" - ], - "id": "revoked_user_id1", - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "name": "revoked_username1" - } - } -} diff --git a/examples/pki/cms/auth_token_revoked.pem b/examples/pki/cms/auth_token_revoked.pem deleted file mode 100644 index 12e4f0ce..00000000 --- a/examples/pki/cms/auth_token_revoked.pem +++ /dev/null @@ -1,79 +0,0 @@ ------BEGIN CMS----- -MIIOTQYJKoZIhvcNAQcCoIIOPjCCDjoCAQExCTAHBgUrDgMCGjCCDFoGCSqGSIb3 -DQEHAaCCDEsEggxHew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIwMzgtMDEtMThUMjE6MTQ6MDda -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogInBsYWNlaG9sZGVyIiwNCiAgICAgICAg -ICAgICJ0ZW5hbnQiOiB7DQogICAgICAgICAgICAgICAgImlkIjogInRlbmFudF9p -ZDEiLA0KICAgICAgICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAg -ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgICAgICJu -YW1lIjogInRlbmFudF9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAgICAgfSwN -CiAgICAgICAgInNlcnZpY2VDYXRhbG9nIjogWw0KICAgICAgICAgICAgew0KICAg -ICAgICAgICAgICAgICJlbmRwb2ludHNfbGlua3MiOiBbXSwNCiAgICAgICAgICAg -ICAgICAiZW5kcG9pbnRzIjogWw0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAu -MTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInB1YmxpY1VSTCI6ICJodHRwOi8v -MTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYx -N2EiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0K -ICAgICAgICAgICAgICAgICJ0eXBlIjogInZvbHVtZSIsDQogICAgICAgICAgICAg -ICAgIm5hbWUiOiAidm9sdW1lIg0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAg -IHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQogICAg -ICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6Ly8x -MjcuMC4wLjE6OTI5Mi92MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVn -aW9uIjogInJlZ2lvbk9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJwdWJsaWNVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5 -MjkyL3YxIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAg -XSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpbWFnZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAiZ2xhbmNlIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQog -ICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAg -ICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6 -Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6 -ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicHVibGlj -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQz -NWU4YTYwZmNmODliYjY2MTdhIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAg -ICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjb21wdXRl -IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJub3ZhIg0KICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xp -bmtzIjogW10sDQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAg -ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWlu -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMToz -NTM1Ny92Mi4wIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJwdWJsaWNVUkwi -OiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAiDQogICAgICAgICAgICAgICAg -ICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJ0eXBl -IjogImlkZW50aXR5IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJrZXlzdG9u -ZSINCiAgICAgICAgICAgIH0NCiAgICAgICAgXSwNCiAgICAgICAgInVzZXIiOiB7 -DQogICAgICAgICAgICAidXNlcm5hbWUiOiAicmV2b2tlZF91c2VybmFtZTEiLA0K -ICAgICAgICAgICAgInJvbGVzX2xpbmtzIjogWw0KICAgICAgICAgICAgICAgICJy -b2xlMSIsDQogICAgICAgICAgICAgICAgInJvbGUyIg0KICAgICAgICAgICAgXSwN -CiAgICAgICAgICAgICJpZCI6ICJyZXZva2VkX3VzZXJfaWQxIiwNCiAgICAgICAg -ICAgICJyb2xlcyI6IFsNCiAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAg -ICAgICAgICJpZCI6ICJmMDNmZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYzMSIs -DQogICAgICAgICAgICAgICAgICAgICJuYW1lIjogInJvbGUxIg0KICAgICAgICAg -ICAgICAgIH0sDQogICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAg -ICAiaWQiOiAiZjAzZmRhOGY4YTMyNDliMmE3MGZiMWYxNzZhN2I2MzEiLA0KICAg -ICAgICAgICAgICAgICAgICAibmFtZSI6ICJyb2xlMiINCiAgICAgICAgICAgICAg -ICB9DQogICAgICAgICAgICBdLA0KICAgICAgICAgICAgIm5hbWUiOiAicmV2b2tl -ZF91c2VybmFtZTEiDQogICAgICAgIH0NCiAgICB9DQp9DQoxggHKMIIBxgIBATCB -pDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYD -VQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5TdGFjazERMA8GA1UECxMIS2V5 -c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25lQG9wZW5zdGFjay5vcmcxFDAS -BgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIB -AA2C5qslA4D7vzbiPJ+PzI6CWKH4fxy2nl6wFneHRlzflRGVtbk7/gwVpgHvVH8+ -FvQEWeXiCvpXDcHUae0YsdB6aifDRkRctoBwWZkSIkLtdLjZTBrwoOBD2cWPTlr6 -gFPp0ARCKVP87YXiKHXStvivZDQFbnBrPTZbGwsCZFXzDYtVPkDvgWOIzHP+olB0 -k0wrFXdTQrr62GmkUdgmY31SBLAmPRlvbFBsdM8R62EVc9Mdk7A8Xenpib6+3hPV -7Jgj5IcC3WWtI1A/WOzuEepfW5AU3bcmsJ4UrsJdZLPYqxy/FS37s7oekBOfSR+Y -WSVmaaTY21X3kOqAQULJTDI= ------END CMS----- diff --git a/examples/pki/cms/auth_token_revoked.pkiz b/examples/pki/cms/auth_token_revoked.pkiz deleted file mode 100644 index aff7b74f..00000000 --- a/examples/pki/cms/auth_token_revoked.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylVkt3ozgT3etXzD6nTwBjJ17MQjyMRSzZYAxIOwMJIB524gePX_8Jk0xn0n2me77xxlCC4ureW1X69k38NNNC5A8db4ebbwAjhHaQ2k8HhrJrTKAT6wcRczxd1w1Jh47Z6h5caunuzUixbnFd10rJ0rev1hZFE2A45hLuRbBQzTRlT8-dnVGFlPEE5-tce0C1e90r_gXxQyrWjvGEyCxwX2joiHWYA8xhg3OpwVupXS-cDnuHlhiHhsiHfKXDnIVZsw_tMu7QDOmowwZWVx5sV56p-gZqwZqb0prDSZCjE9LtI9OHB-0mshacBdk1stwyHtckFkyzqHZGZJV_oYF9Aiy4BaS49svhi_tghJZYwwNTKVTKAm9vCcS9XA5bEdsqo2pxSRbzCxiC7w8ULCQ8rsomscprlAsk1lSOrHb-sm3ES4KXmh2p4hs0dLPImtdDMhBMTrmAVsTW_BjVbj8EhxgN3PM-mPq7orkh2i9dKTYO11VvdqRTmxWHF8GXCkgfK6sJbVc9lShnFVZYThUs497pSbBTqUcbVpFqbZQ55WLFSzKUD4jskinlFdyg6nbHguQYKdNNVO3ykYupxMJh3-0_ogADjP8fhSYDWrVHKvtbb5TvkCzdZp0_XrGHJrd96mq75umE9PSacPNKuJuTivassjntdz0gBpaZl2WEaxVVqLoO7Jxw2hLFzF98aVBHSOY2kVJekiV5iazysh9dGoVCHSA0ncbWbtS-mp-SQesBXiVME3yJ1yLh8u-qgX8p2xTzohv4-lACDFL8FyXAzzNr8u-RW3Rg7aGB3d8i7DNf-0DOmLLLwQBVFMaZbW9fqkUVXqhYGPwv6v9TwjHR0C-YJR-jckQH_ll7Z0B3wdtHhVhIYVw4oCKceFjCvV-uLVMB2GKc8XRKK6QQbk7oWJnvhKo3uHHl1_tgfvGU6bvEApHldwL5Cfi-jW81XmVSsoSzVffYYh4PKIR05mxtiCamzxW8VX9qdfArr_9KDfBv9vvjdu05uMkj-htbatfBOLE8P4n_t1sTXZyTQaVkWTbvKvFIkZskdP-yO_jwe1TNlSHjSh8b5l8Jx0QitiiioLx85Qx8JQ2LEiVeLLaDROxHRXZfFAGfJfmVIj9J3oBE9PZ9QH5VhTI2YCNqpRP3f7M9-D3fizlQu8dkWeRfrP8GWFj2iTW_MEHg-KLfsxC9z8Xh-vNAsUvRXN6G2ZiEYk68q_DRHMQY8_tQaY9RdR7nQ2d3kdJ-DJ7xOreTzxMMCJ8rkXIu2WIux4rffRpltxe-y1gWI8G0EVYuqJdVwly9mM7OlHI7I71oqnxRYS9WqJeIxorbr70xFr2ReeZHqd8G8VDOFTZIxSxTZTzLcI-kdYA66sWiPlDLhGVJJWwrmviPQ9YWk8nadaiWky_sdixkw8GiCCfficSC6JdQatN0-SRONlqbIg1AT9eOhq7V3HzCMLWgvDM1F2vEM1cYFuN9hnXfx63eQ1tLia_B1IMF0bCLGmBCaviOszSb0kuC6eU5ZGJ071qTQ2d8-ODpu3kjZoGXiEPHvjddDB9vifUWI7BV_Gk8ca-ilbe2B7mWFq9ZkVvzRtJ0xwwW1bl8Dokk2n3pWLdE_S1RN73GVdyChQG345ewp8ukjCya7pSyjiq_gOnwtdjStqc1bNAew--nM3E406Czg0ATZMAFn0pmu102GdE2eWhrLybzSqvOEc8n8LJlq0g9L06bbtIfD1acv21OyvLk6kb3Bp4QtCYpT6PzDLZP8n5Wwf1dc7w7blCXcsuzZEWPC3y_UFf1RZVbQ1XWj538TKM7PF89WkDG98-hu9laucfd3RVqao5fpSe-Wbjqw7qfxcfkGDMyu3cbVWXO9m55ThBaeQQnC1p6BKiBVOuHh24fsocHLV3fvzqlVlPJC-zjYfase-fr9IyuxdWfNefEhnpyj9y7N_rcsOeFaGOgxmdovBYUBqbjPhQPrSvL-LHbrifzqzQld_3GOLGNUt_Npe40zarJpFyJOb905oi60SsEslMv7oOYuA9v_Cl5aJhHZhMEX7B9-BPcjtMmMb4frf8Hm6bNOA== \ No newline at end of file diff --git a/examples/pki/cms/auth_token_scoped.json b/examples/pki/cms/auth_token_scoped.json deleted file mode 100644 index 4ea30169..00000000 --- a/examples/pki/cms/auth_token_scoped.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "access": { - "token": { - "expires": "2038-01-18T21:14:07Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "placeholder", - "tenant": { - "id": "tenant_id1", - "enabled": true, - "description": null, - "name": "tenant_name1" - } - }, - "serviceCatalog": [ - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne", - "internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a" - } - ], - "type": "volume", - "name": "volume" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:9292/v1", - "region": "regionOne", - "internalURL": "http://127.0.0.1:9292/v1", - "publicURL": "http://127.0.0.1:9292/v1" - } - ], - "type": "image", - "name": "glance" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne", - "internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a" - } - ], - "type": "compute", - "name": "nova" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:35357/v2.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:35357/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - } - ], - "type": "identity", - "name": "keystone" - } - ], - "user": { - "username": "user_name1", - "roles_links": [ - "role1", - "role2" - ], - "id": "user_id1", - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "name": "user_name1" - } - } -} diff --git a/examples/pki/cms/auth_token_scoped.pem b/examples/pki/cms/auth_token_scoped.pem deleted file mode 100644 index 8754a959..00000000 --- a/examples/pki/cms/auth_token_scoped.pem +++ /dev/null @@ -1,78 +0,0 @@ ------BEGIN CMS----- -MIIONwYJKoZIhvcNAQcCoIIOKDCCDiQCAQExCTAHBgUrDgMCGjCCDEQGCSqGSIb3 -DQEHAaCCDDUEggwxew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIwMzgtMDEtMThUMjE6MTQ6MDda -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogInBsYWNlaG9sZGVyIiwNCiAgICAgICAg -ICAgICJ0ZW5hbnQiOiB7DQogICAgICAgICAgICAgICAgImlkIjogInRlbmFudF9p -ZDEiLA0KICAgICAgICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAg -ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgICAgICJu -YW1lIjogInRlbmFudF9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAgICAgfSwN -CiAgICAgICAgInNlcnZpY2VDYXRhbG9nIjogWw0KICAgICAgICAgICAgew0KICAg -ICAgICAgICAgICAgICJlbmRwb2ludHNfbGlua3MiOiBbXSwNCiAgICAgICAgICAg -ICAgICAiZW5kcG9pbnRzIjogWw0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAu -MTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInB1YmxpY1VSTCI6ICJodHRwOi8v -MTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYx -N2EiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0K -ICAgICAgICAgICAgICAgICJ0eXBlIjogInZvbHVtZSIsDQogICAgICAgICAgICAg -ICAgIm5hbWUiOiAidm9sdW1lIg0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAg -IHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQogICAg -ICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6Ly8x -MjcuMC4wLjE6OTI5Mi92MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVn -aW9uIjogInJlZ2lvbk9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJwdWJsaWNVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5 -MjkyL3YxIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAg -XSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpbWFnZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAiZ2xhbmNlIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQog -ICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAg -ICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6 -Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6 -ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicHVibGlj -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQz -NWU4YTYwZmNmODliYjY2MTdhIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAg -ICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjb21wdXRl -IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJub3ZhIg0KICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xp -bmtzIjogW10sDQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAg -ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWlu -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMToz -NTM1Ny92Mi4wIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJwdWJsaWNVUkwi -OiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAiDQogICAgICAgICAgICAgICAg -ICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJ0eXBl -IjogImlkZW50aXR5IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJrZXlzdG9u -ZSINCiAgICAgICAgICAgIH0NCiAgICAgICAgXSwNCiAgICAgICAgInVzZXIiOiB7 -DQogICAgICAgICAgICAidXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsDQogICAgICAg -ICAgICAicm9sZXNfbGlua3MiOiBbDQogICAgICAgICAgICAgICAgInJvbGUxIiwN -CiAgICAgICAgICAgICAgICAicm9sZTIiDQogICAgICAgICAgICBdLA0KICAgICAg -ICAgICAgImlkIjogInVzZXJfaWQxIiwNCiAgICAgICAgICAgICJyb2xlcyI6IFsN -CiAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICJpZCI6ICJm -MDNmZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYzMSIsDQogICAgICAgICAgICAg -ICAgICAgICJuYW1lIjogInJvbGUxIg0KICAgICAgICAgICAgICAgIH0sDQogICAg -ICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAiaWQiOiAiZjAzZmRh -OGY4YTMyNDliMmE3MGZiMWYxNzZhN2I2MzEiLA0KICAgICAgICAgICAgICAgICAg -ICAibmFtZSI6ICJyb2xlMiINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAg -ICBdLA0KICAgICAgICAgICAgIm5hbWUiOiAidXNlcl9uYW1lMSINCiAgICAgICAg -fQ0KICAgIH0NCn0NCjGCAcowggHGAgEBMIGkMIGeMQowCAYDVQQFEwE1MQswCQYD -VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55dmFsZTESMBAGA1UE -ChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMGCSqGSIb3DQEJARYW -a2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2VsZiBTaWduZWQCAREw -BwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEggEAxyHPqb53KXaWJH1IE6IFp3zzm5vl -zlotcMxMepMRIxQPUDwJrP2ZJwXemQXVTpRa3Aer7hSkCRlyI++mcj/rD4h5Ygb0 -q9sscjfeZB11Y436E4ZhXCdTfrtmKyBlHMqyhTBz64zroN0P+DVH7OLZDX/gqN2U -KTX99HTN+LvUa8VqQYIzsjNv80CU6pog/YOCGPixjMKE9m9xYUr9huKZUxliHtX2 -AHoCfQPhI8nsnNHLzCx6u5xIM7A69ZIDPQ82hSHC58k+g0bq9uflRCixBSD7ulR7 -7ZRJM8IgOgFGpNeuyKcHJsCdPpZS8p1MmDCkwTOt5Kvf7Nopz+Cc325uOA== ------END CMS----- diff --git a/examples/pki/cms/auth_token_scoped.pkiz b/examples/pki/cms/auth_token_scoped.pkiz deleted file mode 100644 index a3177c16..00000000 --- a/examples/pki/cms/auth_token_scoped.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylVkmTmzgUvutXzN2VCotxm0MObMbQSG52ixtLG5DBdrttC_j1I3An6XRSk8wMVS6jJ_H0vfe97dMn9qiGaaG_NOiPi08AWpa1KbH9eEys6pYjxc21I5M9Dhp7ck1xjU4LlLVahme9hJpJNE3d56bmv5i-lYlAd421kjIhKY2yxNxzb1dYQE0uwnpTqw_WwbulQnS1yLFke6dcRHwSezu8ddm-UgNIFAprjkKf6zYrt4fBsUP6kSL-WDuaUifbiqZbu8l7a2FpVg91OHcCpXMCYx7pVgc2xOA2RBHj2nq1NPuUaONBm2bmiiRxdctMr8nve1wSS1V2cO_I2uiKY_sVJPEk4PJD1Iw3pvEdWmGOByRuKzR76E8K2JpvRlOYWU3Wrq7FSr6CUfh2YJ9sEcnbhhZmc8tqhsSU-Mzs5J1P2UfML4fkhIVIx1uvykz5MCoDsfhaM2jMr_IpO3jDKBxlOPYuaSxF4Z5OiNK1x-X68eYMRo_6OXWIcmX-mgM05IIj4s4ZMIdJ0kIhqbEAeTi4A4rDOQ4wTVrUbvSmxoTtBEVl1SMiu0mE5gYmqJrdJ3FxygTpKWvD-u4LiUu2o93dP6IAI4z_jkLlAW67E-YjP7jTdyzWHt3UyxsMLHGyU5t3G1KKaMC3ghg3RLwatXhIWpvgIRwA0iGfBFWFiNpiAc83sV0jgjskGPUu4kZ2GGUezYTmWqzRLjOba3qP0mzL2AGMUyk3wzv3rfxajFyP8FoWNPEH-YEpXP_IGviXtEmQ7PvRX1-ZACMV_4cJ8GvNKv9nzt33YBNYo3f_yGHv_ZXGfJUIYQ1GqCwxLok_3XRgWXjFbGOMf5b_7xTeFY31IjH5U9bc0YF_5t4d0V2hvxSQaQkJYRHQIoICyMEhajamIQBoJiQhpYRbS0DEEPE9M98cOp_g5m10SGP5GgjSG8UMkRn1DPkriCIbTjneVlyxVhZOv-wgyUcUjDpjsdFZEdNkAfrzX4Y6-F2s_44N8G_s_dlcWwYTPay-JWv1NgZOzsuv7P88FdHVpRhZKtYNfWOJZAJPi633LdzB13jPWlkYNTravWB-U3hXxGSrfRY3148-Ax-dBlmKoiBn5lhM9jMj4QdGwHtKfsfIL5RTULDansbod1nIQ12hLFd6tv4h7MGfxT3rAwfvVKz39YfQP4Nk2wyFKV8T5sD7h9GQbK23vji-v28o03o3KQiMSRnIWbVhDeUHBKxQsJYWfi0a43tvNdz71sfnQtSPXQu8daU-E7rmO2XN_u5MTFnY7nFQtSyQBkhcCRO7QgOrn2TVwiAXAA4KVkRh97EOTsgYzLe0_npzC3XUJqYxT0hVwcHiwCa2ehzkLBesLmHhiVoWoqxg_9xQ30w58MV7R4Lv9ky3d-yAvAtMTcmPtCzXplIaKrTMPfs9Q_dINQXrkeuuDGrw0H2lQHMngWlQOwoHw4HK3lT40NBUqLmc0RlEcdUSRaqSB1qE-KyVpIIFHTPPh6pigulwBe1AVJusQRyO0Rl6BtXppNgxaOV8ozowGqjBb_MRG49soHg4ZjOQlIveLWsjJRsVHe6KnFbuk8EIoWpNqJQOOqEQvSa1GqRxcWXDicYUGFSlePVI57pSHanuvp_YDFV1FTZ8GcrR8fnhBZ6Ka4w_z1waumEnBQICw9PlSQwpmuOXQEtDY1bOTjj9LPl8uh4cdbkwrm2OWkvkdNecc8q88Qq03ivo7FKXPokgTtSDB88PHJnrPsGz2usVbDw-n8O63D4f3dNgPKk7a_biR4EmIrWSU4srF7vhtnDD54cdmMmZX1mv-7amy94ZxKBOLw9pcsj4gX19SR_oSrDzM5JO9SyfyVJcbZ6e02A2S-OLTC4FkJf-jddP9bBYPl1m5Voqs3WnWhDXnVq-SMre4j9_3qsCryp28xwfnzDPZaQ4s5GkWyzkGNyiy9Z9sG_4Obsttd3jUhXFonIWc_9Y53m3ibLSDg2P1fIjuZ1Z3WnDTVPBLjy2p8H98gVME7OB9O_T89-mTsWe \ No newline at end of file diff --git a/examples/pki/cms/auth_token_scoped_expired.json b/examples/pki/cms/auth_token_scoped_expired.json deleted file mode 100644 index d9ea0e92..00000000 --- a/examples/pki/cms/auth_token_scoped_expired.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "access": { - "token": { - "expires": "2010-06-02T14:47:34Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "placeholder", - "tenant": { - "id": "tenant_id1", - "enabled": true, - "description": null, - "name": "tenant_name1" - } - }, - "serviceCatalog": [ - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne", - "internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a" - } - ], - "type": "volume", - "name": "volume" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:9292/v1", - "region": "regionOne", - "internalURL": "http://127.0.0.1:9292/v1", - "publicURL": "http://127.0.0.1:9292/v1" - } - ], - "type": "image", - "name": "glance" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne", - "internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a" - } - ], - "type": "compute", - "name": "nova" - }, - { - "endpoints_links": [], - "endpoints": [ - { - "adminURL": "http://127.0.0.1:35357/v2.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:35357/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - } - ], - "type": "identity", - "name": "keystone" - } - ], - "user": { - "username": "user_name1", - "roles_links": [ - "role1", - "role2" - ], - "id": "user_id1", - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "name": "user_name1" - } - } -} diff --git a/examples/pki/cms/auth_token_scoped_expired.pem b/examples/pki/cms/auth_token_scoped_expired.pem deleted file mode 100644 index 43e09f33..00000000 --- a/examples/pki/cms/auth_token_scoped_expired.pem +++ /dev/null @@ -1,76 +0,0 @@ ------BEGIN CMS----- -MIINuQYJKoZIhvcNAQcCoIINqjCCDaYCAQExCTAHBgUrDgMCGjCCC8YGCSqGSIb3 -DQEHAaCCC7cEgguzew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIwMTAtMDYtMDJUMTQ6NDc6MzRa -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogInBsYWNlaG9sZGVyIiwNCiAgICAgICAg -ICAgICJ0ZW5hbnQiOiB7DQogICAgICAgICAgICAgICAgImlkIjogInRlbmFudF9p -ZDEiLA0KICAgICAgICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAg -ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgICAgICJu -YW1lIjogInRlbmFudF9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAgICAgfSwN -CiAgICAgICAgInNlcnZpY2VDYXRhbG9nIjogWw0KICAgICAgICAgICAgew0KICAg -ICAgICAgICAgICAgICJlbmRwb2ludHNfbGlua3MiOiBbXSwNCiAgICAgICAgICAg -ICAgICAiZW5kcG9pbnRzIjogWw0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAu -MTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInB1YmxpY1VSTCI6ICJodHRwOi8v -MTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYx -N2EiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0K -ICAgICAgICAgICAgICAgICJ0eXBlIjogInZvbHVtZSIsDQogICAgICAgICAgICAg -ICAgIm5hbWUiOiAidm9sdW1lIg0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAg -IHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQogICAg -ICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6Ly8x -MjcuMC4wLjE6OTI5Mi92MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVn -aW9uIjogInJlZ2lvbk9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJwdWJsaWNVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5 -MjkyL3YxIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAg -XSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpbWFnZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAiZ2xhbmNlIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xpbmtzIjogW10sDQog -ICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAg -ICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluVVJMIjogImh0dHA6 -Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcm5hbFVSTCI6 -ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicHVibGlj -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQz -NWU4YTYwZmNmODliYjY2MTdhIg0KICAgICAgICAgICAgICAgICAgICB9DQogICAg -ICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjb21wdXRl -IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJub3ZhIg0KICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzX2xp -bmtzIjogW10sDQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAg -ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImFkbWlu -VVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMToz -NTM1Ny92Mi4wIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJwdWJsaWNVUkwi -OiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAiDQogICAgICAgICAgICAgICAg -ICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJ0eXBl -IjogImlkZW50aXR5IiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJrZXlzdG9u -ZSINCiAgICAgICAgICAgIH0NCiAgICAgICAgXSwNCiAgICAgICAgInVzZXIiOiB7 -DQogICAgICAgICAgICAidXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsDQogICAgICAg -ICAgICAicm9sZXNfbGlua3MiOiBbDQogICAgICAgICAgICAgICAgInJvbGUxIiwN -CiAgICAgICAgICAgICAgICAicm9sZTIiDQogICAgICAgICAgICBdLA0KICAgICAg -ICAgICAgImlkIjogInVzZXJfaWQxIiwNCiAgICAgICAgICAgICJyb2xlcyI6IFsN -CiAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICJuYW1lIjog -InJvbGUxIg0KICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgew0K -ICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJyb2xlMiINCiAgICAgICAgICAg -ICAgICB9DQogICAgICAgICAgICBdLA0KICAgICAgICAgICAgIm5hbWUiOiAidXNl -cl9uYW1lMSINCiAgICAgICAgfQ0KICAgIH0NCn0NCjGCAcowggHGAgEBMIGkMIGe -MQowCAYDVQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcT -CVN1bm55dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9u -ZTElMCMGCSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UE -AxMLU2VsZiBTaWduZWQCAREwBwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEggEAw7K9 -7FaxXE6QNbsWmTAo/mtppDB2hv2DCwxMnjaZuOlV3g7UGnF8mxHjWd2Pcj1r0oGb -0iACE9qmoZVHTPWU6WWBClAIF/bcs6Y+5S10bCu1uRVrzUCsLEbbJOLxBZG1qiEZ -opLn6pBIOY8ovxcoKKmI56JgsqVGclZM5yH9Z9E5hSZgMREJZFZcVHA3pTJeTjc2 -9Mpb3RS5Q/FXf2nP09YA4Mp9+J15gFH/YuhBQiyo+LqvHtg+DdWdxcM3keAaTuxw -Z8Cd26T+cTv1iS5qXcykd8OP7V0eIF7i39wshXGm6B9XpwFEYiLTZy7398O/yeGd -izImJNpCowBA0Pyr8w== ------END CMS----- diff --git a/examples/pki/cms/auth_token_scoped_expired.pkiz b/examples/pki/cms/auth_token_scoped_expired.pkiz deleted file mode 100644 index 5824b4ef..00000000 --- a/examples/pki/cms/auth_token_scoped_expired.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylVtuSmzgQfddX7PtUKiDsGfOQBy4yhrHEcLd4MzAGZLA99pjb16_Ak2QySW2yu66iDC3RnO5zulufPvGfigyT_KVhb3z4BLBpmnZOrcdjbBZNShQn1Y7c9jho_JdqioM6zVdWah6c9RxrBtM0dZ8amvdieGYiAd1BK2XLjSxHeU6F594qKCRVKuHSLtUH8-A2WxheTXbM-doplYgYR-6Obhy-rpQAM6XFpdBiT-jspdNj_9gR_dgS8ViuNaWMN0W73VhV2pv3pmb2WEft2lcgv_pQRwKwmSPZDAtRaV5MzTrF2rjRahNjyeKoaBLDrdLbmhBH8yI5ODdkdXilkXUBcTQZhPQQVuMXt9ENWmaMG-bCBlZ77E0O-LNYjaHwsKqkXl6zpXwFo_Ftwz7eEJbWVZsZVZOUHIkxFxOjk3dey1_ieTnEJwpDnW7cIjHkw-gMRNKl5NB4XuVTcnCH0TjaaOS-bqN5GOzbCdF25QqpfmzWA-pJP2vXTLnyfM0AGVK4lmi3HqhAWVxjGJcUYhEPzkCiYEZ92sY1qW29KinjK35WmOWIyKpiWDVggqpZfRxlpwTOn5I6KG-5mAvxZoy7-0cUYITx31GoIqB1d6Ji6Pk3-o7Zym3tctFg35SmOLVZZ7NcIgNtMoYawtyS1HSIa4vRIRgA0bEY-0VBmFpTSGd2ZJWE0Y5AVO5CYWSHU-a2Cayu2YrsEqO6bm8qTTacHcA5nadGcOO-li_ZyPUIr-aiiT7YD9zh6kfWwL-kbY7Zvh_z9ZUJMFLxf5gAv_asin-W3H0PbN8cs_tHCXufr20kFjEMSjBC5YXxGnvTlw68Cq-UL4z65_X_zuHN0dgvYkM8JdUNHfhn7p0R3RV7C0gME8aMK6AmjPhYwENY2QaCABsxi1k-p7UJCUMSvVXmW0JnE9y0Dg_bSL76cP5GMUdkhD1HfgFhaOGpxutCyFbK_bpfdJilIwpOHbq3dd7ENBlib_ZLqYPfaf13bIB_E-_P4VoymOjh_S1eqc0onFSUL_z_PDXR5Ws2spStqvaNJZZAsc027je5g696T2oZjh7X2q1hfnN4c8Rty30SVdePOQMfk4Z5iRI_5eGY3PYzI8EHRsB7Sn7HyC-ctyDjvX0bkd9VoYh1peW10vPnH2QP_kz3fA4c3FO22pcfpH8G8aYaMkO-xjyBtxfDId6Yb3NxvH8_UKbn3eTAR5MzkPJuwwfKDwh4o-AjLfjaNMb73qyE96NPTGHYj1MLvE2lPoFd9Z2yan9LJm25bPfUL2oupAEzZ06ZVZCB90-2rLGfQkD9jDdR3H3sgxMyDvOtrL9-ucY6qWMDzWJWFHgw-XSOzJ76Ka8Fs4u5PEnNJcob9s8D9S2Ug5i9TyT4Hs_09Y5vkHe-oSnpsc3zlaHkSMWmsefXM3aOraZQPXScJWqRiJ1LCzRnMhiotcJgQGus7A1FDJCmYs0RUIeY4qg5CVUl9bWQiEk9n2dcdDw8D6uKAabNBbZ8Sa2Sigg0ImfsolZvJ8dr1Bbrb1T7qMIa_nY-4scjCygujfgZaJ5KbpPUoZKMjg43R-ta7uMBBVg1J1RKh9cBDC9xqfrbKLvyw4nGHaBWbenysZ3pSnFsdef9iQ2pqqPwwxdShifbKSSRDulneAkzL_1s95acEXAHC8PNXUdeP_Qrz9qeXvW6znWfvOrq4irIun8XtKKPVnfijJEHMs9DT9RWUmE9KjynDFjbJfPxS7Mx0iWWFs9RWj46L3Z3V587XM1PWwNCXoTJ2UNDv1d9vvuz9tLXV_kxDWYYgqHYd8_N6XzoH2b-xWpw0y_gJtAsxErjRb5G4RbKz_YBO2VeLXPDpyxSbVs8N2ZTBVgCiztMAyErXrdbb7N_Me8fcjVnq9dBsKTF4alod0-SuyzE3LNe81ZdFU6TCv48WWXN-hB7O_B8DmemaSyebLh7CO6kaJFerYooCIa2zek7UjVGq6ck30Okq4_3s0OV2WpyLwkwwsqXL2A6MSOifz89_w1E1sSW \ No newline at end of file diff --git a/examples/pki/cms/auth_token_unscoped.json b/examples/pki/cms/auth_token_unscoped.json deleted file mode 100644 index 844cebd5..00000000 --- a/examples/pki/cms/auth_token_unscoped.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "access": { - "token": { - "expires": "2112-08-17T15:35:34Z", - "issued_at": "2002-01-18T21:14:07Z", - "id": "01e032c996ef4406b144335915a41e79" - }, - "serviceCatalog": {}, - "user": { - "username": "user_name1", - "roles_links": [], - "id": "c9c89e3be3ee453fbf00c7966f6d3fbd", - "roles": [ - { - "id": "359da42d31c04437a32812aeb79e9c0b", - "name": "role1" - }, - { - "id": "581af19726fa4af5bda745789ab2bf2b", - "name": "role2" - } - ], - "name": "user_name1" - } - } -} diff --git a/examples/pki/cms/auth_token_unscoped.pem b/examples/pki/cms/auth_token_unscoped.pem deleted file mode 100644 index 274ac386..00000000 --- a/examples/pki/cms/auth_token_unscoped.pem +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CMS----- -MIIE9gYJKoZIhvcNAQcCoIIE5zCCBOMCAQExCTAHBgUrDgMCGjCCAwMGCSqGSIb3 -DQEHAaCCAvQEggLwew0KICAgICJhY2Nlc3MiOiB7DQogICAgICAgICJ0b2tlbiI6 -IHsNCiAgICAgICAgICAgICJleHBpcmVzIjogIjIxMTItMDgtMTdUMTU6MzU6MzRa -IiwNCiAgICAgICAgICAgICJpc3N1ZWRfYXQiOiAiMjAwMi0wMS0xOFQyMToxNDow -N1oiLA0KICAgICAgICAgICAgImlkIjogIjAxZTAzMmM5OTZlZjQ0MDZiMTQ0MzM1 -OTE1YTQxZTc5Ig0KICAgICAgICB9LA0KICAgICAgICAic2VydmljZUNhdGFsb2ci -OiB7fSwNCiAgICAgICAgInVzZXIiOiB7DQogICAgICAgICAgICAidXNlcm5hbWUi -OiAidXNlcl9uYW1lMSIsDQogICAgICAgICAgICAicm9sZXNfbGlua3MiOiBbXSwN -CiAgICAgICAgICAgICJpZCI6ICJjOWM4OWUzYmUzZWU0NTNmYmYwMGM3OTY2ZjZk -M2ZiZCIsDQogICAgICAgICAgICAicm9sZXMiOiBbDQogICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAiaWQiOiAiMzU5ZGE0MmQzMWMwNDQzN2Ez -MjgxMmFlYjc5ZTljMGIiLA0KICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJy -b2xlMSINCiAgICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAgIHsNCiAg -ICAgICAgICAgICAgICAgICAgImlkIjogIjU4MWFmMTk3MjZmYTRhZjViZGE3NDU3 -ODlhYjJiZjJiIiwNCiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAicm9sZTIi -DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgXSwNCiAgICAgICAgICAg -ICJuYW1lIjogInVzZXJfbmFtZTEiDQogICAgICAgIH0NCiAgICB9DQp9DQoxggHK -MIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5TdGFjazERMA8G -A1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25lQG9wZW5zdGFj -ay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIaMA0GCSqGSIb3 -DQEBAQUABIIBAMmrhRIUjSd+SLUAYn+18MDB8MXiaiF+FJQbu86IFW3OpL86ksvg -CTP44Rvu1F4vvoZAQ60/tOfFVNTnBgnMv0NEfl4huiFqYrXjCphnNFQ5OYnmU6LR -bFV+dvjZXWUn0wJDroUUEjbgyy/mqUnULzQgUzyK7Ho8T0dWahQc7EFMNVjoeKfa -K7DeRe9trNNHM8anKVaeKhpWIfzbxiwIwypukce6wVGfdhaP+58jeFnGwHUIsY8V -8rzWj9UN46ko61piMAZljcktbrpqw2fDJ1H9Xl23G83rnXY7uVLQWUe7fRcUFtQt -gQvKsGkN2hqlOgMT/FxFM3HC8kcl3wmzrNA= ------END CMS----- diff --git a/examples/pki/cms/auth_token_unscoped.pkiz b/examples/pki/cms/auth_token_unscoped.pkiz deleted file mode 100644 index 34f93f46..00000000 --- a/examples/pki/cms/auth_token_unscoped.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJxdVNmWqjoQfecr7nuvs5pBW30MIWKiCSKT5A1QZqQdEOTrb7DPHVmLIVWVqr03Vfn1S1w6MjH7A1JnWvySKMZGa4dk23KcPxMG7AS2wlaVEILZDAIbDdAFGz3zbkZGoTnZo5kJnavp4FiTDBttQCSMfImyzIzPL5KHKqsTjRZWoS_w5fCMVL_DZZsJ33eiMYUHhzQ82sIPComWoKeF3FNHHqy1_aJuOzCj7ZnSFjsICn7M--hI6uSFvzDEwo9eOxfMdi7SfAMpklVSRdxyUOA7huSbw3dgTwOvpyMpLbdSeRDKzABqWCLxpiNzq4EFSBYxmmQ5ZDVVSlT_dWrqknssP5nre6wmbwqp02f44o_8iH9Tmr5JFwZKPdGSfhvSuFk_uIvesJNmdedHlsZm3UU_WsTHKVFTV9Mm3NB5OGZz7rJCEo-au7ZCVV5woUc4JnNW8oY19sgbUuFiQkCesemP0-ZAuxdR8CMgHb25xE3BRQTTgPbMsEemopGW2UCbdR2WiahSl9TEb2RvlM6kEXnF6lBTQV_aQcHrL2ilN6PBuqFupVGBInQPOS_9QhTRmOFpllHnYUkEUlK8kTXzXIoD7w3nzdvFRerL09_4W6T_a5QelRUNsf6aGioJoSQ6rc8iu8_4bIAlwHrGfB14LnC9AY6A_KxDF9S-S-17D-3Q8G0bo54YtoscierABIqH9IEST_O7-FKrYSD4HXCPwDt4i_p6n5h-52kH0aX3Ablg_5P47koQPerzkcmxOheieD3u_z0Xlb7O-Y0f6_Fkrjru6c8pUfKTqIs1cpHowe5R9q5koP7h8mBo8Jp9c5GQC0boP4MEmJ5V17wqzFUv64L-WgLAEROnxy40lpf0Fg28fjkQr5bP1g0-Qt-trp_4RXab1bDZlQvFPkffLGmr62wLSLTYS9b2MhKrIzeowvOwgP35VOcfVbq7nLEefJzqb1nfpgf1dh0sdWM-QmW3WJwrvzBhh9bFl0R2kU3U3eqYwodf6ddV2OfzzAwWt0fqJI62dwS7fUn0wd2q22tM5LzxcyqjjMNZt46kpJtbY5PjW218jXuv1s3ncAZhvFAeymKFu2I8xOuxSZf-vH76-_IKeLy0WKvq7Hgbv6A0dJ-seV45vZufmqwrsZ68hlxvo2ZBFrkV55blvzbp_nOZmZes3LycHQkPVlzKz9N2OXxJS00ui6s_aPNNIDjeWsvY-vuP9mOuIel96iFm_HMC_gm2VKmF \ No newline at end of file diff --git a/examples/pki/cms/auth_v3_token_revoked.json b/examples/pki/cms/auth_v3_token_revoked.json deleted file mode 100644 index f2ddf29c..00000000 --- a/examples/pki/cms/auth_v3_token_revoked.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "token": { - "catalog": [ - { - "endpoints": [ - { - "id": "3b5e554bcf114f2483e8a1be7a0506d1", - "interface": "admin", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "54abd2dc463c4ba4a72915498f8ecad1", - "interface": "internal", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "70a7efa4b1b941968357cc43ae1419ee", - "interface": "public", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "5707c3fc0a294703a3c638e9cf6a6c3a", - "type": "volume", - "name": "volume" - }, - { - "endpoints": [ - { - "id": "92217a3b95394492859bc49fd474382f", - "interface": "admin", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "f20563bdf66f4efa8a1f11d99b672be1", - "interface": "internal", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "375f9ba459a447738fb60fe5fc26e9aa", - "interface": "public", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - } - ], - "id": "15c21aae6b274a8da52e0a068e908aac", - "type": "image", - "name": "glance" - }, - { - "endpoints": [ - { - "id": "edbd9f50f66746ae9ed11dc3b1ae35da", - "interface": "admin", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "9e03c46c80a34a159cb39f5cb0498b92", - "interface": "internal", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "1df0b44d92634d59bd0e0d60cf7ce432", - "interface": "public", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "2f404fdb89154c589efbc10726b029ec", - "type": "compute", - "name": "nova" - }, - { - "endpoints": [ - { - "id": "a4501e141a4b4e14bf282e7bffd81dc5", - "interface": "admin", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "3d17e3227bfc4483b58de5eaa584e360", - "interface": "internal", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "8cd4b957090f4ca5842a22e9a74099cd", - "interface": "public", - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne" - } - ], - "id": "c5d926d566424e4fba4f80c37916cde5", - "type": "identity", - "name": "keystone" - } - ], - "issued_at": "2002-01-18T21:14:07Z", - "expires_at": "2038-01-18T21:14:07Z", - "audit_ids": ["ZzzZ2ZZYqT8OzfUVvrjEITQ", "cCCCCCctTzO1-XUk5STybw"], - "project": { - "enabled": true, - "description": null, - "name": "tenant_name1", - "id": "tenant_id1", - "domain": { - "id": "domain_id1", - "name": "domain_name1" - } - }, - "user": { - "name": "revoked_username1", - "id": "revoked_user_id1", - "domain": { - "id": "domain_id1", - "name": "domain_name1" - } - }, - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "methods": [ - "password" - ] - } -} diff --git a/examples/pki/cms/auth_v3_token_revoked.pem b/examples/pki/cms/auth_v3_token_revoked.pem deleted file mode 100644 index ca2bf06b..00000000 --- a/examples/pki/cms/auth_v3_token_revoked.pem +++ /dev/null @@ -1,123 +0,0 @@ ------BEGIN CMS----- -MIIWqQYJKoZIhvcNAQcCoIIWmjCCFpYCAQExCTAHBgUrDgMCGjCCFLYGCSqGSIb3 -DQEHAaCCFKcEghSjew0KICAgICJ0b2tlbiI6IHsNCiAgICAgICAgImNhdGFsb2ci -OiBbDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6 -IFsNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAg -ICAgImlkIjogIjNiNWU1NTRiY2YxMTRmMjQ4M2U4YTFiZTdhMDUwNmQxIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAiYWRtaW4iLA0KICAg -ICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3 -NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAgICAg -ICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAg -ICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJpZCI6ICI1NGFiZDJkYzQ2M2M0YmE0YTcyOTE1NDk4 -ZjhlY2FkMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjog -ImludGVybmFsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1cmwiOiAiaHR0 -cDovLzEyNy4wLjAuMTo4Nzc2L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODli -YjY2MTdhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVn -aW9uT25lIg0KICAgICAgICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAg -ICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAiaWQiOiAiNzBhN2VmYTRi -MWI5NDE5NjgzNTdjYzQzYWUxNDE5ZWUiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgImludGVyZmFjZSI6ICJwdWJsaWMiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUz -NDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAg -InJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0NCiAg -ICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJpZCI6ICI1NzA3YzNm -YzBhMjk0NzAzYTNjNjM4ZTljZjZhNmMzYSIsDQogICAgICAgICAgICAgICAgInR5 -cGUiOiAidm9sdW1lIiwNCiAgICAgICAgICAgICAgICAibmFtZSI6ICJ2b2x1bWUi -DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAg -ICJlbmRwb2ludHMiOiBbDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAg -ICAgICAgICAgICAgICAgICJpZCI6ICI5MjIxN2EzYjk1Mzk0NDkyODU5YmM0OWZk -NDc0MzgyZiIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjog -ImFkbWluIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDov -LzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJy -ZWdpb24iOiAicmVnaW9uT25lIg0KICAgICAgICAgICAgICAgICAgICB9LA0KICAg -ICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAiaWQi -OiAiZjIwNTYzYmRmNjZmNGVmYThhMWYxMWQ5OWI2NzJiZTEiLA0KICAgICAgICAg -ICAgICAgICAgICAgICAgImludGVyZmFjZSI6ICJpbnRlcm5hbCIsDQogICAgICAg -ICAgICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcuMC4wLjE6OTI5Mi92 -MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogInJlZ2lvbk9u -ZSINCiAgICAgICAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAgICAgICAg -ew0KICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogIjM3NWY5YmE0NTlhNDQ3 -NzM4ZmI2MGZlNWZjMjZlOWFhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJp -bnRlcmZhY2UiOiAicHVibGljIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1 -cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIg0KICAgICAgICAgICAgICAg -ICAgICB9DQogICAgICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICAiaWQi -OiAiMTVjMjFhYWU2YjI3NGE4ZGE1MmUwYTA2OGU5MDhhYWMiLA0KICAgICAgICAg -ICAgICAgICJ0eXBlIjogImltYWdlIiwNCiAgICAgICAgICAgICAgICAibmFtZSI6 -ICJnbGFuY2UiDQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAg -ICAgICAgICAgICJlbmRwb2ludHMiOiBbDQogICAgICAgICAgICAgICAgICAgIHsN -CiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICJlZGJkOWY1MGY2Njc0NmFl -OWVkMTFkYzNiMWFlMzVkYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJmYWNlIjogImFkbWluIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJ1cmwi -OiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc0L3YxLjEvNjRiNmYzZmJjYzUzNDM1ZThh -NjBmY2Y4OWJiNjYxN2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lv -biI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAg -ICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICI5 -ZTAzYzQ2YzgwYTM0YTE1OWNiMzlmNWNiMDQ5OGI5MiIsDQogICAgICAgICAgICAg -ICAgICAgICAgICAiaW50ZXJmYWNlIjogImludGVybmFsIiwNCiAgICAgICAgICAg -ICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc0L3YxLjEv -NjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAgICAgICAgICAg -ICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAg -ICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJpZCI6ICIxZGYwYjQ0ZDkyNjM0ZDU5YmQwZTBkNjBjZjdjZTQz -MiIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjogInB1Ymxp -YyIsDQogICAgICAgICAgICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcu -MC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdh -IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25l -Ig0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgXSwNCiAg -ICAgICAgICAgICAgICAiaWQiOiAiMmY0MDRmZGI4OTE1NGM1ODllZmJjMTA3MjZi -MDI5ZWMiLA0KICAgICAgICAgICAgICAgICJ0eXBlIjogImNvbXB1dGUiLA0KICAg -ICAgICAgICAgICAgICJuYW1lIjogIm5vdmEiDQogICAgICAgICAgICB9LA0KICAg -ICAgICAgICAgew0KICAgICAgICAgICAgICAgICJlbmRwb2ludHMiOiBbDQogICAg -ICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6 -ICJhNDUwMWUxNDFhNGI0ZTE0YmYyODJlN2JmZmQ4MWRjNSIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAiaW50ZXJmYWNlIjogImFkbWluIiwNCiAgICAgICAgICAg -ICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTozNTM1Ny92MyIs -DQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lvbk9uZSIN -CiAgICAgICAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAgICAgICAgew0K -ICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogIjNkMTdlMzIyN2JmYzQ0ODNi -NThkZTVlYWE1ODRlMzYwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRl -cmZhY2UiOiAiaW50ZXJuYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVy -bCI6ICJodHRwOi8vMTI3LjAuMC4xOjM1MzU3L3YzIiwNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJyZWdpb24iOiAiUmVnaW9uT25lIg0KICAgICAgICAgICAgICAg -ICAgICB9LA0KICAgICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAg -ICAgICAgICAiaWQiOiAiOGNkNGI5NTcwOTBmNGNhNTg0MmEyMmU5YTc0MDk5Y2Qi -LA0KICAgICAgICAgICAgICAgICAgICAgICAgImludGVyZmFjZSI6ICJwdWJsaWMi -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAu -MC4xOjUwMDAvdjMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6 -ICJSZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAg -ICAgICBdLA0KICAgICAgICAgICAgICAgICJpZCI6ICJjNWQ5MjZkNTY2NDI0ZTRm -YmE0ZjgwYzM3OTE2Y2RlNSIsDQogICAgICAgICAgICAgICAgInR5cGUiOiAiaWRl -bnRpdHkiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogImtleXN0b25lIg0KICAg -ICAgICAgICAgfQ0KICAgICAgICBdLA0KICAgICAgICAiaXNzdWVkX2F0IjogIjIw -MDItMDEtMThUMjE6MTQ6MDdaIiwNCiAgICAgICAgImV4cGlyZXNfYXQiOiAiMjAz -OC0wMS0xOFQyMToxNDowN1oiLA0KICAgICAgICAicHJvamVjdCI6IHsNCiAgICAg -ICAgICAgICJlbmFibGVkIjogdHJ1ZSwNCiAgICAgICAgICAgICJkZXNjcmlwdGlv -biI6IG51bGwsDQogICAgICAgICAgICAibmFtZSI6ICJ0ZW5hbnRfbmFtZTEiLA0K -ICAgICAgICAgICAgImlkIjogInRlbmFudF9pZDEiLA0KICAgICAgICAgICAgImRv -bWFpbiI6IHsNCiAgICAgICAgICAgICAgICAiaWQiOiAiZG9tYWluX2lkMSIsDQog -ICAgICAgICAgICAgICAgIm5hbWUiOiAiZG9tYWluX25hbWUxIg0KICAgICAgICAg -ICAgfQ0KICAgICAgICB9LA0KICAgICAgICAidXNlciI6IHsNCiAgICAgICAgICAg -ICJuYW1lIjogInJldm9rZWRfdXNlcm5hbWUxIiwNCiAgICAgICAgICAgICJpZCI6 -ICJyZXZva2VkX3VzZXJfaWQxIiwNCiAgICAgICAgICAgICJkb21haW4iOiB7DQog -ICAgICAgICAgICAgICAgImlkIjogImRvbWFpbl9pZDEiLA0KICAgICAgICAgICAg -ICAgICJuYW1lIjogImRvbWFpbl9uYW1lMSINCiAgICAgICAgICAgIH0NCiAgICAg -ICAgfSwNCiAgICAgICAgInJvbGVzIjogWw0KICAgICAgICAgICAgew0KICAgICAg -ICAgICAgICAgICJpZCI6ICJmMDNmZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYz -MSIsDQogICAgICAgICAgICAgICAgIm5hbWUiOiAicm9sZTEiDQogICAgICAgICAg -ICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJpZCI6ICJmMDNm -ZGE4ZjhhMzI0OWIyYTcwZmIxZjE3NmE3YjYzMSIsDQogICAgICAgICAgICAgICAg -Im5hbWUiOiAicm9sZTIiDQogICAgICAgICAgICB9DQogICAgICAgIF0sDQogICAg -ICAgICJtZXRob2RzIjogWw0KICAgICAgICAgICAgInBhc3N3b3JkIg0KICAgICAg -ICBdDQogICAgfQ0KfQ0KMYIByjCCAcYCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJ -BgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYD -VQQKEwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkB -FhZrZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIB -ETAHBgUrDgMCGjANBgkqhkiG9w0BAQEFAASCAQCy1xOK1+nQy8tL3fORdWkcp0Y5 -88cNgl4sXmJOE1TOOEauMyVWE188gtxHelVDCFWr8kICALvAnPX0UbIhoEaxscey -mvcUazUMP2WWSsBMgSXBfbl6amTZp5KMgpMmAuGjP1xok3yvOecEF6Szh8yE3Q5O -sNEKsMI5UiJTDU7WWSUp1Zs7E4UvFjAepZGhIQWOCxSvEnrl3Mfw1f7HWKDBlijR -4XnPqJPiTmYLjzyDmi31GOHWZM4nZxShHfidLblPV4AyA/gsCh27/cZxYW/Q+cyL -wfQogs4g7XfNgLdDHlbvv7NCS06RhydhLeiqNUcCp4hnZZC16KDPWzJ2Ql5y ------END CMS----- diff --git a/examples/pki/cms/auth_v3_token_revoked.pkiz b/examples/pki/cms/auth_v3_token_revoked.pkiz deleted file mode 100644 index cf27adff..00000000 --- a/examples/pki/cms/auth_v3_token_revoked.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJydWEt3ozgT3etXfPucPgPCpOPFLHgZ47FEwDws7QxODELYTvzA8OunsJ3uPDrT6a9z-uSE4FLdqntvlfLtG_wzHdej_7PIrP_hGyKeR4qGTf7ZcK845tQIcmsDzx5sy7LHgWUEzsmKjLG5ip_tFbFcYVnWNnCt2ZM78zIN2YEzNhbwcBM7q9WT-dBOlAzvZVZ6t954V2ZpoizcYZW38PNoV-buqMu15TGvg3I-a1bIW0-OmZt0ntisUm1XLtKg9Euj5MLoeB0WvssGLCIttWVJakcjLi9Jyk604wXFHkakc8qpZZRZPdrzGZxiTdoMnySZTYZTy_zu1bLqg3s1awjmFYuK2nedjohAZ2JSINqZNROjmkQ5ZtGypIKcvLKBD-hFlsbnbPJ6uOORVz4myg4OkA9jc5vXSTfHIwWdowuvId1qT2xnT6IiJsK5JVFwS-zl4hxsbUJWW8m0Ht6rrNahRJD6YTkabrl9gcLd4Z6l8tC_AAXdcusMq8qwWixS_RFq9CZDdC7Y9UNzfH548taXVCF4CQU-n7YcT1Q-6z8YyhzTdjE3lUU6PJwhZOtkl1lvcS_d5MBSXXkXVLB5WGTucP3SNcRTvcrd4TZbh69aqSt8PqlZSuWlA6Mq62Gd65G02QXWZjkOG4BwdySRp02FcSDW4OSLlUY7dlwK50hFWNKaAR_g5C7uqE1UHhUFFdA5zAZ-OikRFUAKfCkgtGbd47pUeCI5lsesGh6AH33614J6HROJpFGssJrWiESOwoWn-DaVQJATq2ONRYZKbF69ItMBatLyeiSuZOshyxxqhgBPH13N6-ZcvMU4VHJ7c5x2TkvbQXOGFm0GtMvxVGOnaccUJngNrCwZJipQOehoGgPfWcMhJR84zwT8KloWl6JdoZQXmvN0uc2wfp_V8Rk2ehEPjcKC1UHLXaJQAV_upKAuiEdUJxoFei8qntKiJ9wj8KEnWQ8D5TUvGL5yfpwAcaT4Vbs-6xb6ars-6xb6j3aB9h2Np6B71zsxUSkkqrAPwSkGiDbAgQ5CG6Xk0K7eXUBdeu5eqQwSXqaqvAjnqj4Ra6BQAR0QELz1o0BDBCIRDF9dIf2UQh8czDpavPeEHwF7TYDVvUgA_b8aeCkq-lnVClLyeg38Ca11RITXVxf4XamkqxRqQyA71llNFD_lFbVzBdyq5eWvaY1e8_qLtNaBXG1P6x4a-h1Vf9q819CIdawOawpaoG5Sg0MXqPd4kgJVUw_TblJCb99Q9XdMRZ9T9WtFRe_NgnZJDdQtaF_IKFBAxp0P06inNY8g7c7DPJIFu5IPvWbfIlULjt9iJ1EiiBgVLI0xE54GCh1w11FJHTdgPBj5bqwTu4AXyPsRt87c0aHHf60J2HzYZBjaOCb9gMn6OqH3hWJpuF-kg3Ow5XyyuzCyUJZj43ba3p2IyPsaQUudW9_ONUStISazwQer-qpTod_2Pw1LbsuaRib0n2nU5iBjULDtnMC9OgSTGR6Agbif9_8qMphUzQdo6DNsX4WG_tSFX6D5aQwLB1EQrckA3KWD_oL7SsEE0blI4Luh-FFR-v1i8R_URn_mwkFP7QOZ3WHwSTA2gADzTdCIgOaTfrRhWKIEFyvwAxCXcDR2ofoVyuC68lx0EWFdoremOaq4MEtqhxWkDj4ZVgAL2mhK4gYQHDwTUwm233prdXmeTMuxbK7UFbDGNMt5-M6JJzW1DQVWvtK3-ykVQsYrHey-ZJ3TwJbmgUiM1k8T8d6Js3qI2Y8JnRz42Dz2nLgsnfuzvaF3Y7vgrrqFFn7F2jqonYpoC4RpPxYqflWoN5BqR6GRceqnEklhMjERShKFvecNSL9c1Lzm9qrnufoyRD7Oi4szg_R36Gsc6Ckca-DE3Xu29p44-4yuBAcwM2LYi70-MxiowYBgT_XdUNI0KVgUDxB1YZwL44-c-HWm6G2qIBDbALqSj04sfz3eAII3YDhQ-tFGO0MnLsgXO6pvBy2LvLZ3YNBA44PQuPVxDYAdKZSQ9nY5rt7gZ11ypjO3Y9BE0AJUYGO_NzFQLwH7B1bWtEI8it-78TOfy27p9qm-nJh0fO5dV_3wmKWj7cuV6MeW9nNjl7BgnjGChanXvl8_JIfnZ5cF9HIoernm8Dk_LnBSzbX-tMn1xddT68M757sDuq7xxTKFOvQXj-vQ8OT29kFu2lRueZ4Eg0jb1knCcV5vR7MkDC_0pjaC6WcHmCrJeHtPZipL0p0aq6HO1vn5Wge0hWteIvloWCwv87OFVrdT0MM0cgYosT3ov6P4wtBS2EIeI9cy8k2zWo1dY-WYxHMr-P9Agk1jGcxOgmDkNDAbg11jBcxG8MB1mkkSd86UGJVrqLFjmcQKFOfkCCMwVzQxjTyyEqpmta4vQUCgxBkxjfO7yCrIJNJMmUmqgNqeSeg0dnM-aeo0xfRHSyNHEov8uPLCjXdihCxFUFU916BNdWJkfaD1JdC0Hra8c2JieueTjBOZxjjZ8dKMFunywFO4V8NhyGzY6J9mYBvFprGD15dwxzQDA-7TjtGOxMIPR9FjE37XlON2OLSOB7sjD972Dj3vk-d2KBcPs-i21Uf3T1YNbT7l2DUf13g_cx-GOztaP5Uj9n3HlcmoCOybMtQmpSKD5BQhO1wbnuf8VQxq81BFdydp7pVVfCrNm25YBtSST48zfdt8V7ARb2Ot3DaMTjl_rr2tk_ylofomW_jOatpsRxv_xr9ZVVYs75RsIBUdVHqzte-8gzmYPVZW87zOHruTtDb5Kdb8h0X2qHkomd3WT8Pd6GCnj3KCT-U8NZXn440q0yM7TXLn4K6G08aLk0qtd_e3M3pj4XEi56UbYWMNV1823R3Nm6ySHdnj1nkw_MhV8NPqefKPqdLh-AFnnXW_N-82BSmq2VgeqvvWHAyCv_9G5z-CONT--QeRfwEmaLr4 \ No newline at end of file diff --git a/examples/pki/cms/auth_v3_token_scoped.json b/examples/pki/cms/auth_v3_token_scoped.json deleted file mode 100644 index 0fd000a0..00000000 --- a/examples/pki/cms/auth_v3_token_scoped.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "token": { - "methods": [ - "password" - ], - "roles": [ - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role1" - }, - { - "id": "f03fda8f8a3249b2a70fb1f176a7b631", - "name": "role2" - } - ], - "issued_at": "2002-01-18T21:14:07Z", - "expires_at": "2038-01-18T21:14:07Z", - "audit_ids": ["VcxU2JYqT8OzfUVvrjEITQ", "qNUTIJntTzO1-XUk5STybw"], - "project": { - "id": "tenant_id1", - "domain": { - "id": "domain_id1", - "name": "domain_name1" - }, - "enabled": true, - "description": null, - "name": "tenant_name1" - }, - "catalog": [ - { - "endpoints": [ - { - "id": "3b5e554bcf114f2483e8a1be7a0506d1", - "interface": "admin", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "54abd2dc463c4ba4a72915498f8ecad1", - "interface": "internal", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "70a7efa4b1b941968357cc43ae1419ee", - "interface": "public", - "url": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "5707c3fc0a294703a3c638e9cf6a6c3a", - "type": "volume", - "name": "volume" - }, - { - "endpoints": [ - { - "id": "92217a3b95394492859bc49fd474382f", - "interface": "admin", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "f20563bdf66f4efa8a1f11d99b672be1", - "interface": "internal", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - }, - { - "id": "375f9ba459a447738fb60fe5fc26e9aa", - "interface": "public", - "url": "http://127.0.0.1:9292/v1", - "region": "regionOne" - } - ], - "id": "15c21aae6b274a8da52e0a068e908aac", - "type": "image", - "name": "glance" - }, - { - "endpoints": [ - { - "id": "edbd9f50f66746ae9ed11dc3b1ae35da", - "interface": "admin", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "9e03c46c80a34a159cb39f5cb0498b92", - "interface": "internal", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - }, - { - "id": "1df0b44d92634d59bd0e0d60cf7ce432", - "interface": "public", - "url": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", - "region": "regionOne" - } - ], - "id": "2f404fdb89154c589efbc10726b029ec", - "type": "compute", - "name": "nova" - }, - { - "endpoints": [ - { - "id": "a4501e141a4b4e14bf282e7bffd81dc5", - "interface": "admin", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "3d17e3227bfc4483b58de5eaa584e360", - "interface": "internal", - "url": "http://127.0.0.1:35357/v3", - "region": "RegionOne" - }, - { - "id": "8cd4b957090f4ca5842a22e9a74099cd", - "interface": "public", - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne" - } - ], - "id": "c5d926d566424e4fba4f80c37916cde5", - "type": "identity", - "name": "keystone" - } - ], - "user": { - "domain": { - "id": "domain_id1", - "name": "domain_name1" - }, - "name": "user_name1", - "id": "user_id1" - } - } -} diff --git a/examples/pki/cms/auth_v3_token_scoped.pem b/examples/pki/cms/auth_v3_token_scoped.pem deleted file mode 100644 index 50641147..00000000 --- a/examples/pki/cms/auth_v3_token_scoped.pem +++ /dev/null @@ -1,123 +0,0 @@ ------BEGIN CMS----- -MIIWmgYJKoZIhvcNAQcCoIIWizCCFocCAQExCTAHBgUrDgMCGjCCFKcGCSqGSIb3 -DQEHAaCCFJgEghSUew0KICAgICJ0b2tlbiI6IHsNCiAgICAgICAgIm1ldGhvZHMi -OiBbDQogICAgICAgICAgICAicGFzc3dvcmQiDQogICAgICAgIF0sDQogICAgICAg -ICJyb2xlcyI6IFsNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiaWQi -OiAiZjAzZmRhOGY4YTMyNDliMmE3MGZiMWYxNzZhN2I2MzEiLA0KICAgICAgICAg -ICAgICAgICJuYW1lIjogInJvbGUxIg0KICAgICAgICAgICAgfSwNCiAgICAgICAg -ICAgIHsNCiAgICAgICAgICAgICAgICAiaWQiOiAiZjAzZmRhOGY4YTMyNDliMmE3 -MGZiMWYxNzZhN2I2MzEiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogInJvbGUy -Ig0KICAgICAgICAgICAgfQ0KICAgICAgICBdLA0KICAgICAgICAiaXNzdWVkX2F0 -IjogIjIwMDItMDEtMThUMjE6MTQ6MDdaIiwNCiAgICAgICAgImV4cGlyZXNfYXQi -OiAiMjAzOC0wMS0xOFQyMToxNDowN1oiLA0KICAgICAgICAicHJvamVjdCI6IHsN -CiAgICAgICAgICAgICJpZCI6ICJ0ZW5hbnRfaWQxIiwNCiAgICAgICAgICAgICJk -b21haW4iOiB7DQogICAgICAgICAgICAgICAgImlkIjogImRvbWFpbl9pZDEiLA0K -ICAgICAgICAgICAgICAgICJuYW1lIjogImRvbWFpbl9uYW1lMSINCiAgICAgICAg -ICAgIH0sDQogICAgICAgICAgICAiZW5hYmxlZCI6IHRydWUsDQogICAgICAgICAg -ICAiZGVzY3JpcHRpb24iOiBudWxsLA0KICAgICAgICAgICAgIm5hbWUiOiAidGVu -YW50X25hbWUxIg0KICAgICAgICB9LA0KICAgICAgICAiY2F0YWxvZyI6IFsNCiAg -ICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAiZW5kcG9pbnRzIjogWw0KICAg -ICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAiaWQi -OiAiM2I1ZTU1NGJjZjExNGYyNDgzZThhMWJlN2EwNTA2ZDEiLA0KICAgICAgICAg -ICAgICAgICAgICAgICAgImludGVyZmFjZSI6ICJhZG1pbiIsDQogICAgICAgICAg -ICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3Ni92MS82 -NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAg -ICAgICAgICAgICAicmVnaW9uIjogInJlZ2lvbk9uZSINCiAgICAgICAgICAgICAg -ICAgICAgfSwNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAg -ICAgICAgICAgImlkIjogIjU0YWJkMmRjNDYzYzRiYTRhNzI5MTU0OThmOGVjYWQx -IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAiaW50ZXJu -YWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3 -LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2Ei -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUi -DQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIHsN -CiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICI3MGE3ZWZhNGIxYjk0MTk2 -ODM1N2NjNDNhZTE0MTllZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiaW50 -ZXJmYWNlIjogInB1YmxpYyIsDQogICAgICAgICAgICAgICAgICAgICAgICAidXJs -IjogImh0dHA6Ly8xMjcuMC4wLjE6ODc3Ni92MS82NGI2ZjNmYmNjNTM0MzVlOGE2 -MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9u -IjogInJlZ2lvbk9uZSINCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAg -ICAgICAgIF0sDQogICAgICAgICAgICAgICAgImlkIjogIjU3MDdjM2ZjMGEyOTQ3 -MDNhM2M2MzhlOWNmNmE2YzNhIiwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJ2 -b2x1bWUiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogInZvbHVtZSINCiAgICAg -ICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgImVuZHBv -aW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAg -ICAgICAgICAgImlkIjogIjkyMjE3YTNiOTUzOTQ0OTI4NTliYzQ5ZmQ0NzQzODJm -IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAiYWRtaW4i -LA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAu -MC4xOjkyOTIvdjEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6 -ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAg -ICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICJpZCI6ICJmMjA1 -NjNiZGY2NmY0ZWZhOGExZjExZDk5YjY3MmJlMSIsDQogICAgICAgICAgICAgICAg -ICAgICAgICAiaW50ZXJmYWNlIjogImludGVybmFsIiwNCiAgICAgICAgICAgICAg -ICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAicmVnaW9uT25lIg0KICAg -ICAgICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAgICAgICB7DQogICAg -ICAgICAgICAgICAgICAgICAgICAiaWQiOiAiMzc1ZjliYTQ1OWE0NDc3MzhmYjYw -ZmU1ZmMyNmU5YWEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImludGVyZmFj -ZSI6ICJwdWJsaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJo -dHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0N -CiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAgICAgICAgICJpZCI6ICIxNWMy -MWFhZTZiMjc0YThkYTUyZTBhMDY4ZTkwOGFhYyIsDQogICAgICAgICAgICAgICAg -InR5cGUiOiAiaW1hZ2UiLA0KICAgICAgICAgICAgICAgICJuYW1lIjogImdsYW5j -ZSINCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAg -ICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAg -ICAgICAgICAgICAgICAgICAgImlkIjogImVkYmQ5ZjUwZjY2NzQ2YWU5ZWQxMWRj -M2IxYWUzNWRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2Ui -OiAiYWRtaW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgInVybCI6ICJodHRw -Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5 -YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogInJl -Z2lvbk9uZSINCiAgICAgICAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAg -ICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogIjllMDNjNDZj -ODBhMzRhMTU5Y2IzOWY1Y2IwNDk4YjkyIiwNCiAgICAgICAgICAgICAgICAgICAg -ICAgICJpbnRlcmZhY2UiOiAiaW50ZXJuYWwiLA0KICAgICAgICAgICAgICAgICAg -ICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNm -YmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSIsDQogICAgICAgICAgICAgICAgICAg -ICAgICAicmVnaW9uIjogInJlZ2lvbk9uZSINCiAgICAgICAgICAgICAgICAgICAg -fSwNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAg -ICAgImlkIjogIjFkZjBiNDRkOTI2MzRkNTliZDBlMGQ2MGNmN2NlNDMyIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZhY2UiOiAicHVibGljIiwNCiAg -ICAgICAgICAgICAgICAgICAgICAgICJ1cmwiOiAiaHR0cDovLzEyNy4wLjAuMTo4 -Nzc0L3YxLjEvNjRiNmYzZmJjYzUzNDM1ZThhNjBmY2Y4OWJiNjYxN2EiLA0KICAg -ICAgICAgICAgICAgICAgICAgICAgInJlZ2lvbiI6ICJyZWdpb25PbmUiDQogICAg -ICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBdLA0KICAgICAgICAg -ICAgICAgICJpZCI6ICIyZjQwNGZkYjg5MTU0YzU4OWVmYmMxMDcyNmIwMjllYyIs -DQogICAgICAgICAgICAgICAgInR5cGUiOiAiY29tcHV0ZSIsDQogICAgICAgICAg -ICAgICAgIm5hbWUiOiAibm92YSINCiAgICAgICAgICAgIH0sDQogICAgICAgICAg -ICB7DQogICAgICAgICAgICAgICAgImVuZHBvaW50cyI6IFsNCiAgICAgICAgICAg -ICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgImlkIjogImE0NTAx -ZTE0MWE0YjRlMTRiZjI4MmU3YmZmZDgxZGM1IiwNCiAgICAgICAgICAgICAgICAg -ICAgICAgICJpbnRlcmZhY2UiOiAiYWRtaW4iLA0KICAgICAgICAgICAgICAgICAg -ICAgICAgInVybCI6ICJodHRwOi8vMTI3LjAuMC4xOjM1MzU3L3YzIiwNCiAgICAg -ICAgICAgICAgICAgICAgICAgICJyZWdpb24iOiAiUmVnaW9uT25lIg0KICAgICAg -ICAgICAgICAgICAgICB9LA0KICAgICAgICAgICAgICAgICAgICB7DQogICAgICAg -ICAgICAgICAgICAgICAgICAiaWQiOiAiM2QxN2UzMjI3YmZjNDQ4M2I1OGRlNWVh -YTU4NGUzNjAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImludGVyZmFjZSI6 -ICJpbnRlcm5hbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAidXJsIjogImh0 -dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjMiLA0KICAgICAgICAgICAgICAgICAgICAg -ICAgInJlZ2lvbiI6ICJSZWdpb25PbmUiDQogICAgICAgICAgICAgICAgICAgIH0s -DQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAg -ICJpZCI6ICI4Y2Q0Yjk1NzA5MGY0Y2E1ODQyYTIyZTlhNzQwOTljZCIsDQogICAg -ICAgICAgICAgICAgICAgICAgICAiaW50ZXJmYWNlIjogInB1YmxpYyIsDQogICAg -ICAgICAgICAgICAgICAgICAgICAidXJsIjogImh0dHA6Ly8xMjcuMC4wLjE6NTAw -MC92MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAicmVnaW9uIjogIlJlZ2lv -bk9uZSINCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIF0s -DQogICAgICAgICAgICAgICAgImlkIjogImM1ZDkyNmQ1NjY0MjRlNGZiYTRmODBj -Mzc5MTZjZGU1IiwNCiAgICAgICAgICAgICAgICAidHlwZSI6ICJpZGVudGl0eSIs -DQogICAgICAgICAgICAgICAgIm5hbWUiOiAia2V5c3RvbmUiDQogICAgICAgICAg -ICB9DQogICAgICAgIF0sDQogICAgICAgICJ1c2VyIjogew0KICAgICAgICAgICAg -ImRvbWFpbiI6IHsNCiAgICAgICAgICAgICAgICAiaWQiOiAiZG9tYWluX2lkMSIs -DQogICAgICAgICAgICAgICAgIm5hbWUiOiAiZG9tYWluX25hbWUxIg0KICAgICAg -ICAgICAgfSwNCiAgICAgICAgICAgICJuYW1lIjogInVzZXJfbmFtZTEiLA0KICAg -ICAgICAgICAgImlkIjogInVzZXJfaWQxIg0KICAgICAgICB9DQogICAgfQ0KfQ0K -MYIByjCCAcYCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYD -VQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sx -ETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVu -c3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkq -hkiG9w0BAQEFAASCAQCPCzpknZOfDONpHDWGrYTeyirjGGjrJem2EF2qsJ4K1x/V -guNLX1AfRnRUC95wSpGS5VCQ+OSfSFmLjJQOnMqLZ1L2MkVfn0CIkqig19sgRZ+O -hpi+0TpJ6XlCWRERJEICCOAHZ/M2iiiVFbFkIGtaJLw3HcXFreV+nEBuQSeIGH/H -FjnmocYu9vy612YT47HcyQKNMaku3QBLzFTSTiGkS4ft9yT2pNMbHZsMmysaRKWl -SfuA/DZHT6zi5D4lkxDBCexf3JAw4kOQSf/dirfDUKmIy4VPeAOuO1u86hN/coIS -JvgAJGOVUxtZCQ9256dUvKa1pLpQAgW/Ok3oPulS ------END CMS----- diff --git a/examples/pki/cms/auth_v3_token_scoped.pkiz b/examples/pki/cms/auth_v3_token_scoped.pkiz deleted file mode 100644 index 3365dfe5..00000000 --- a/examples/pki/cms/auth_v3_token_scoped.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJylWEl34rwS3etXvH2fPu0BElh6wthBcmw8IO2wnWDLNiRh8PDrXwlId4bu70u_lyxycKBUt-reWyW-f4cf3bId8h8DL8WL7wg7Ds5b6t7tmFOcMqL5mbGDZ2vTMEzbNzTf6oxQm-ub6MXcYMPmhmHsfNtYPttLJ1WR6VtzbQ0Pt5G12Tx1D70rpcqhTkvnxpnvyzSJpbU9rbIeXs_2ZWbPhkzNT1njl6tlu0HO1j2ldjw4fLdJ1H25TvzSK7WScW1gTVB4Nh3REPfErEvcWCq2WYkT2pGBFURxFIQHq1wYWpk2swNbwimG26dKV-OlO10Y-q3T1JUI7jS0xQqraFg0nm0NmPtjyt0CkUFvKJ81OMwUGuYl4bhzyhY-MC7SJDpnkzXTPQud8jGW9nBA_TDXn7ImHlbKTELn6Nxp8bA5YNM64LCIMLducOjfYDNfn4NtdcjqqaaqgCeyCk5pMnsSdUKiUD9x29MDTerjSqkrvHTEaUeayPUFwvVD9fT87AJRKxFLxgVtupoZoupBnyeR-ODT-bXhSuL_6TZ4hEM-Qcvt-IhoMpZWyvnh9Q1BnSmkX690aZ1Mj-L0dBvv0_kZP6eroEjt6fa1ayKDKrOnT3DKm1aOJbZyG5qQa_qzKgVol3rEfXrJbpfPgxZ55eSEQ0ddcO2IjVHn8Y1KBnrKuXUiPChJQ4EPcPIQDcTEMguLgnDonEJHXuKWiHAghXLhArRm-5o2EKxmSn1Kq-mRXQp6rYszUB7XJIwk2pAG4dCSGHckzyQ1EKSjTaTSUJOxyao3ZDpCwXrWzPiVbAJynUFBEeAR0eWsac-VXc8DKTN3p8Vg9aQftWdo4W5EhkxZqLRbDFSinDXAypIqWAYq-wNJIuA7bRmk5AHnKYd_hXlxKdoVSnmhOUvyp1QZ36dNdIaNXklEwgD44PfMxhLh8Gu7BbFBPLzqSOiPhahYQgpmWuUjqBBUe4aBsoYVVLlyfh6XqV3z37XrT91CX23Xn7qF_qFdoH1LZQno3nY6yisJh5XiQXCiAEQT4EAHoY11zaBdwl2cbTDO7CvPQcK5ENKZ3ldP4JEKCuXQAQ7Bey_0VYQhElbgdyhqLyHQB0uhAyk-Cec14BY0AQp-lQD6XzXwWlT0q6oVpOQIDfwNrccIc0dUF_hdyXioJGJCIDMa0wZLXsIqYmYSuFXPyt_TGr3l9RdpPQZy9YLWAhr6N6r-snmnJSEdaBM0BLRA7LgBhy6Q8HicAFUTRyGDW0Jv31H135iK_kzVrxUVfTQLMsQNULcgopChL4GMBw-mkaA1CyHtwVFYWBf0Sj70ln3rRC6Y8h47DmOO-aygSaRQ7qig0BGzLRk3UQvGoyDPjsbYLOAN-OOI26b27CjwX2tSp03Qpgq0cY7FgElFndDHQtEkOKyT0TlYvnL3F0YWUj7Xbhb9pMM8EzWCllo3npmpiBhTBS9Hn6zqq06F_rX_SVAys25IqEP_qUpMBjIGBZtWB-41IJjM8AAMxP5z_68ig5nYfoKG_oTtq9DQ37rwKzQviWDhwBIiDR6BuwzQX3DfmlOOx4zH8FeTvLAoPbFY_AO10d-5sC-ofcTLiQI-CcYGEGC-cRJi0HwsRpsCSxRnfAN-AOLilkovVL9CGV1XnosuQmVco_emOasY10tiBhWkDj4ZVAAL2qjX2PYhOHimQmqw_d7Zyvl5MuXzur1Sl6eK3Oar4IMTuw0xNQlWvtIzxZQKIOPNGOy-pIPVwpbmgEi03kti_tGJ02aq0J8TOj6yuX4SnLgsnYezvaEPY7tgtiy2r69Y2wC1kxHpgTD950JFbwr1DlJjSSTUOjGVcAKTifKgxmEgPG-ExXLRsIaZG8Fz-XWIfJ4XF2cG6e_R1zggKByp4MTDR7YKT1z-ia5Y8WFmRLAXOyIzGKj-CCuO7NlBTZK4oGE0QsSGcc61v3Lit5mi96mCQEwN6Io_O3H9-_EGEJwRVXxJjDYyaGNsg3wVS_ZMv6eh0wsHBg20HgiNGZ_XANiRghrSfsrn1Tv8dIjPdGZmBJrwe4AKbBR7EwX1YrB_YGVDKsTC6KMbv7BVPeS2SPX1xHhgK-fTqi9ajP6fVV8ciq6nypkS9--39ivzzqe7l3V_e97YizwByLPpE4P5gMSAcGrGH2ZRv6zrLjaL-4eGxfGW9esqduPZdTZG4zi26juoV_RQTbpFXMTrIQ5RPK_LvHfP2l6vyJAncSXuQj-vQqbz-6vQVp5i6uioh4ukllFxwWw3a7_dsFFncM3RNyTWtSjUwqgzBs29vIZpWMch9vet4VMz9n0HWa1r-qG1xLpma3Jk6R12IzU-pttaoQlc_wKntbTzm--str7P4JoTqbAWK_vOCrV7dIm8Dw3rUD-sCNxax1DlqHXeXYcrHcbPr_ZG-kkEyiAQgkjHVHW3OPBba3M-ybTaQ8iSrnFm5IlBQAaIrHf3Z43om-q5qEobTVtJB_wzTVtCHfQyJe6ErBKVzTaj52ktJzfLb5v18ZmC1e32cXCI5qRZzslkMg823voBTYYq2m8GfXVblmo0dM3LjN3xqVkYCzr6sV1KyTqii1l6WDem8cKauebfL3da5hH1YX0kB3S3s8JH95Yrw_PIcQ-yjZenh4leSlL5GLTsx2EXLshhkdaPVjtbG_2tGo-Ml930B6tGP4y9h0aBP1TLYtZNb8udfW9NW0t2T1M6dLvxMdzcDMroZlOOlIexdFw6M4Ybgp-rKB-k7Y2fHb4hecCPk-Tbg_zUV3f7LNaH2_HtbLr99qwVnTxedF1u3DkvvgwjZpJr_SLQ_Uh6Zg-LZnFaqgnaNo8_3Nq_XZh-86yufGsepL68H-fDj6bFE6dcNhN0_rLDIuavLz7-Cz0ItdI= \ No newline at end of file diff --git a/examples/pki/cms/revocation_list.der b/examples/pki/cms/revocation_list.der deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/pki/cms/revocation_list.json b/examples/pki/cms/revocation_list.json deleted file mode 100644 index 766c69c9..00000000 --- a/examples/pki/cms/revocation_list.json +++ /dev/null @@ -1 +0,0 @@ -{"revoked": [{"expires": "2112-08-14T17:58:48Z", "id": "db98ed2af6c6707bec6dc6c6892789a0"}, {"expires": "2112-08-14T17:58:48Z", "id": "15ce05fd491b79791068ed80a9c7f5e7"}, {"expires": "2112-08-14T17:58:48Z", "id": "db98ed2af6c6707bec6dc6c6892789a0"}, {"expires": "2112-08-14T17:58:48Z", "id": "15ce05fd491b79791068ed80a9c7f5e7"}]} \ No newline at end of file diff --git a/examples/pki/cms/revocation_list.pem b/examples/pki/cms/revocation_list.pem deleted file mode 100644 index 0e81998b..00000000 --- a/examples/pki/cms/revocation_list.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CMS----- -MIIDTwYJKoZIhvcNAQcCoIIDQDCCAzwCAQExCTAHBgUrDgMCGjCCAVwGCSqGSIb3 -DQEHAaCCAU0EggFJeyJyZXZva2VkIjogW3siZXhwaXJlcyI6ICIyMTEyLTA4LTE0 -VDE3OjU4OjQ4WiIsICJpZCI6ICJkYjk4ZWQyYWY2YzY3MDdiZWM2ZGM2YzY4OTI3 -ODlhMCJ9LCB7ImV4cGlyZXMiOiAiMjExMi0wOC0xNFQxNzo1ODo0OFoiLCAiaWQi -OiAiMTVjZTA1ZmQ0OTFiNzk3OTEwNjhlZDgwYTljN2Y1ZTcifSwgeyJleHBpcmVz -IjogIjIxMTItMDgtMTRUMTc6NTg6NDhaIiwgImlkIjogImRiOThlZDJhZjZjNjcw -N2JlYzZkYzZjNjg5Mjc4OWEwIn0sIHsiZXhwaXJlcyI6ICIyMTEyLTA4LTE0VDE3 -OjU4OjQ4WiIsICJpZCI6ICIxNWNlMDVmZDQ5MWI3OTc5MTA2OGVkODBhOWM3ZjVl -NyJ9XX0xggHKMIIBxgIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkGA1UEBhMCVVMx -CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNVBAoTCU9wZW5T -dGFjazERMA8GA1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEWFmtleXN0b25l -QG9wZW5zdGFjay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgERMAcGBSsOAwIa -MA0GCSqGSIb3DQEBAQUABIIBAGn4kryxJudTZYMf32gKnoNHeAXRb97CoCXiTgs2 -gu/blX/fwMdrL8GLg2puYR07XBgjo56vMsD94ZIRyhcS1lFti9veQHt7Xp8kbR8l -nbx9fsOhMxUHLRnxioieA9T1ykP8ZvYV3hYCeXkIYhPgD4lAAAmNq99ZxBRS3csE -DP+Xz1+UYvT6Qm/NWRuj7WIjofneIB7gT6L5irsU0qtMCQeqI3dsP9GSsy4HJvBR -BBIzQ7fEMRCGTADbk4ml+6Dx+Jm5SO80NvinzxCjO3DbkcEG1pQ3RGVEn3gyzg2a -ssaRU4ycbYACA99K5UzCtSj8glGXFa1cnx42nSn2LbfJP1M= ------END CMS----- diff --git a/examples/pki/cms/revocation_list.pkiz b/examples/pki/cms/revocation_list.pkiz deleted file mode 100644 index 566d3318..00000000 --- a/examples/pki/cms/revocation_list.pkiz +++ /dev/null @@ -1 +0,0 @@ -PKIZ_eJx9VElzszgUvPMr5p5KBbPY5vAdtGAsYokAYr0ZbIvdSXDM8usHO1Uzl6lRlQ6v1dVPr6vrvb4uB5oWYX8h6j-KV4kSgvmQ2O_XlBT3nAE3R9cFczFCYB4QcM0RcbCHIvjGgiKrWvBwsJD_ZfkkUyXsmntwXMBANoXY2efJntI4vR-VsCbVVURqX6ZxMRxju8knsiaITJSb04ED7cBNWQqxqTpVoDmVq0Ul6QmyP1P0INp1UtVaGrlTEiVKMicqxacyjaiSWvRRaw4nquTgpqDINg4IbkgbarnVLD-gpVOCklbmSEt5cJA8sp07svm6cvBVdnbX8oBAeYzcUnoSeVilHKzS1pUdvivZXKsONwdWFU2KxZDwpmJKskp5Xl78QSxjNuc9_MzbcJYec5KKjJSTG8XiRrkXUJ6vGRdrhosjKQdB2ubpB2m90uEPUbtIq7RiVT5ITLGbZE7r5S6A0GmVa05kDqSTe7L_fwMf_kn_bSAZWcQaisM2xa5OI7KMlOuUA8WxwtrBsHAiqqZV2Ehsso04lkch9u9LJuAoCAQcwU-MYFeZ7xQIC6wCE3oUMm4eKKh_68X6MKSjhGZgQ8FCCAQHNYPUI4MJEhy67t4cGn6K9J9znBaZFYxmBdxf7pWjwBjSSOfSydpVx9n0KNg-ldFIia-Eeq5696wNRpuDCor6q6hLyxhkiFwz2rW35hwzOVP0RnKtp9L8FJr0e97m4w4D_7cT5WjFmsxKRKA0XdaGNRCPZrkF_d4BAzlKFMj_5HqJNQRuAODiBbA6rf6eRvvnxNOEXlRFvHdXtj-D2MuMDbqiuOSiVyTx85Y18dtloKfvw9Y6COXzJ_HkTQxFddXXd9pjQ0uJNxW5v2p2t9K4n939bRN_buvM2zZSl43GpXcKOgb7g9eN5bU8A4Ovpvpjm96TUC0SdI5rkhQfAmsNAKBlX4aRjtDz1bw3JfzxEs-rlyC587XbvrHI-6k20ZK7S3cmcCP4-qCX330gf90ocs9fRD31H4bl95O2t-_QkyAks7u5mNRDFgc4q7W2eVnj8cVudd_ZyuxedvOIKkdd3nLTWn26qmeFZqeKaRbKUer7oxdoU54lAAHDeNeDGd38aisaK94dV3k3akrnd8ohu9gfK_pHeu4hk-F_d9Lf2fB_ww== \ No newline at end of file diff --git a/examples/pki/gen_cmsz.py b/examples/pki/gen_cmsz.py deleted file mode 100644 index 6840c08e..00000000 --- a/examples/pki/gen_cmsz.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/python - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json -import os - -from keystoneclient.common import cms -from keystoneclient import utils - -CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) - - -def make_filename(*args): - return os.path.join(CURRENT_DIR, *args) - - -def generate_revocation_list(): - REVOKED_TOKENS = ['auth_token_revoked', 'auth_v3_token_revoked'] - revoked_list = [] - for token in REVOKED_TOKENS: - with open(make_filename('cms', '%s.pkiz' % name), 'r') as f: - token_data = f.read() - id = utils.hash_signed_token(token_data.encode('utf-8')) - revoked_list.append({ - 'id': id, - "expires": "2112-08-14T17:58:48Z" - }) - with open(make_filename('cms', '%s.pem' % name), 'r') as f: - pem_data = f.read() - token_data = cms.cms_to_token(pem_data).encode('utf-8') - id = utils.hash_signed_token(token_data) - revoked_list.append({ - 'id': id, - "expires": "2112-08-14T17:58:48Z" - }) - revoked_json = json.dumps({"revoked": revoked_list}) - with open(make_filename('cms', 'revocation_list.json'), 'w') as f: - f.write(revoked_json) - encoded = cms.pkiz_sign(revoked_json, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME) - with open(make_filename('cms', 'revocation_list.pkiz'), 'w') as f: - f.write(encoded) - - encoded = cms.cms_sign_data(revoked_json, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME) - with open(make_filename('cms', 'revocation_list.pem'), 'w') as f: - f.write(encoded) - - -CA_CERT_FILE_NAME = make_filename('certs', 'cacert.pem') -SIGNING_CERT_FILE_NAME = make_filename('certs', 'signing_cert.pem') -SIGNING_KEY_FILE_NAME = make_filename('private', 'signing_key.pem') -EXAMPLE_TOKENS = ['auth_token_revoked', - 'auth_token_unscoped', - 'auth_token_scoped', - 'auth_token_scoped_expired', - 'auth_v3_token_scoped', - 'auth_v3_token_revoked'] - - -# Helper script to generate the sample data for testing -# the signed tokens using the existing JSON data for the -# MII-prefixed tokens. Uses the keys and certificates -# generated in gen_pki.sh. -def generate_der_form(name): - derfile = make_filename('cms', '%s.der' % name) - with open(derfile, 'w') as f: - derform = cms.cms_sign_data(text, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME, cms.PKIZ_CMS_FORM) - f.write(derform) - -for name in EXAMPLE_TOKENS: - json_file = make_filename('cms', name + '.json') - pkiz_file = make_filename('cms', name + '.pkiz') - with open(json_file, 'r') as f: - string_data = f.read() - - # validate the JSON - try: - token_data = json.loads(string_data) - except ValueError as v: - raise SystemExit('%s while processing token data from %s: %s' % - (v, json_file, string_data)) - - text = json.dumps(token_data).encode('utf-8') - - # Uncomment to record the token uncompressed, - # useful for debugging - # generate_der_form(name) - - encoded = cms.pkiz_sign(text, - SIGNING_CERT_FILE_NAME, - SIGNING_KEY_FILE_NAME) - - # verify before writing - cms.pkiz_verify(encoded, - SIGNING_CERT_FILE_NAME, - CA_CERT_FILE_NAME) - - with open(pkiz_file, 'w') as f: - f.write(encoded) - - generate_revocation_list() diff --git a/examples/pki/gen_pki.sh b/examples/pki/gen_pki.sh deleted file mode 100755 index 8e2b59f9..00000000 --- a/examples/pki/gen_pki.sh +++ /dev/null @@ -1,208 +0,0 @@ -#!/bin/bash - -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# These functions generate the certificates and signed tokens for the tests. - -DIR=`dirname "$0"` -CURRENT_DIR=`cd "$DIR" && pwd` -CERTS_DIR=$CURRENT_DIR/certs -PRIVATE_DIR=$CURRENT_DIR/private -CMS_DIR=$CURRENT_DIR/cms - - -function rm_old { - rm -rf $CERTS_DIR/*.pem - rm -rf $PRIVATE_DIR/*.pem -} - -function cleanup { - rm -rf *.conf > /dev/null 2>&1 - rm -rf index* > /dev/null 2>&1 - rm -rf *.crt > /dev/null 2>&1 - rm -rf newcerts > /dev/null 2>&1 - rm -rf *.pem > /dev/null 2>&1 - rm -rf serial* > /dev/null 2>&1 -} - -function generate_ca_conf { - echo ' -[ req ] -default_bits = 2048 -default_keyfile = cakey.pem -default_md = default - -prompt = no -distinguished_name = ca_distinguished_name - -x509_extensions = ca_extensions - -[ ca_distinguished_name ] -serialNumber = 5 -countryName = US -stateOrProvinceName = CA -localityName = Sunnyvale -organizationName = OpenStack -organizationalUnitName = Keystone -emailAddress = keystone@openstack.org -commonName = Self Signed - -[ ca_extensions ] -basicConstraints = critical,CA:true -' > ca.conf -} - -function generate_ssl_req_conf { - echo ' -[ req ] -default_bits = 2048 -default_keyfile = keystonekey.pem -default_md = default - -prompt = no -distinguished_name = distinguished_name - -[ distinguished_name ] -countryName = US -stateOrProvinceName = CA -localityName = Sunnyvale -organizationName = OpenStack -organizationalUnitName = Keystone -commonName = localhost -emailAddress = keystone@openstack.org -' > ssl_req.conf -} - -function generate_cms_signing_req_conf { - echo ' -[ req ] -default_bits = 2048 -default_keyfile = keystonekey.pem -default_md = default - -prompt = no -distinguished_name = distinguished_name - -[ distinguished_name ] -countryName = US -stateOrProvinceName = CA -localityName = Sunnyvale -organizationName = OpenStack -organizationalUnitName = Keystone -commonName = Keystone -emailAddress = keystone@openstack.org -' > cms_signing_req.conf -} - -function generate_signing_conf { - echo ' -[ ca ] -default_ca = signing_ca - -[ signing_ca ] -dir = . -database = $dir/index.txt -new_certs_dir = $dir/newcerts - -certificate = $dir/certs/cacert.pem -serial = $dir/serial -private_key = $dir/private/cakey.pem - -default_days = 21360 -default_crl_days = 30 -default_md = default - -policy = policy_any - -[ policy_any ] -countryName = supplied -stateOrProvinceName = supplied -localityName = optional -organizationName = supplied -organizationalUnitName = supplied -emailAddress = supplied -commonName = supplied -' > signing.conf -} - -function setup { - touch index.txt - echo '10' > serial - generate_ca_conf - mkdir newcerts -} - -function check_error { - if [ $1 != 0 ] ; then - echo "Failed! rc=${1}" - echo 'Bailing ...' - cleanup - exit $1 - else - echo 'Done' - fi -} - -function generate_ca { - echo 'Generating New CA Certificate ...' - openssl req -x509 -newkey rsa:2048 -days 21360 -out $CERTS_DIR/cacert.pem -keyout $PRIVATE_DIR/cakey.pem -outform PEM -config ca.conf -nodes - check_error $? -} - -function ssl_cert_req { - echo 'Generating SSL Certificate Request ...' - generate_ssl_req_conf - openssl req -newkey rsa:2048 -keyout $PRIVATE_DIR/ssl_key.pem -keyform PEM -out ssl_req.pem -outform PEM -config ssl_req.conf -nodes - check_error $? - #openssl req -in req.pem -text -noout -} - -function cms_signing_cert_req { - echo 'Generating CMS Signing Certificate Request ...' - generate_cms_signing_req_conf - openssl req -newkey rsa:2048 -keyout $PRIVATE_DIR/signing_key.pem -keyform PEM -out cms_signing_req.pem -outform PEM -config cms_signing_req.conf -nodes - check_error $? - #openssl req -in req.pem -text -noout -} - -function issue_certs { - generate_signing_conf - echo 'Issuing SSL Certificate ...' - openssl ca -in ssl_req.pem -config signing.conf -batch - check_error $? - openssl x509 -in $CURRENT_DIR/newcerts/10.pem -out $CERTS_DIR/ssl_cert.pem - check_error $? - echo 'Issuing CMS Signing Certificate ...' - openssl ca -in cms_signing_req.pem -config signing.conf -batch - check_error $? - openssl x509 -in $CURRENT_DIR/newcerts/11.pem -out $CERTS_DIR/signing_cert.pem - check_error $? -} - -function check_openssl { - echo 'Checking openssl availability ...' - which openssl - check_error $? -} - -JSON_FILES="${CMS_DIR}/auth_token_revoked.json ${CMS_DIR}/auth_token_unscoped.json ${CMS_DIR}/auth_token_scoped.json ${CMS_DIR}/auth_token_scoped_expired.json ${CMS_DIR}/revocation_list.json ${CMS_DIR}/auth_v3_token_scoped.json ${CMS_DIR}/auth_v3_token_revoked.json" - -function gen_sample_cms { - for json_file in $JSON_FILES - do - openssl cms -sign -in $json_file -nosmimecap -signer $CERTS_DIR/signing_cert.pem -inkey $PRIVATE_DIR/signing_key.pem -outform PEM -nodetach -nocerts -noattr -out ${json_file/.json/.pem} - done -} - diff --git a/examples/pki/private/cakey.pem b/examples/pki/private/cakey.pem deleted file mode 100644 index 1c93ee18..00000000 --- a/examples/pki/private/cakey.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCl8906EaRpibQF -cCBWfxzLi5x/XpZ9iL6UX92NrSJxcDbaGws7s+GtjgDy8UOEonesRWTeqQEZtHpC -3/UHHOnsA8F6ha/pq9LioqT7RehCnZCLBJwh5Ct+lclpWs15SkjJD2LTDkjox0eA -9nOBx+XDlWyU/GAyqx5Wsvg/Kxr0iod9/4IcJdnSdUjq4v0Cxg/zNk08XPJX+F0b -UDhgdUf7JrAmmS5LA8wphRnbIgtVsf6VN9HrbqtHAJDxh8gEfuwdhEW1df1fBtZ+ -6WMIF3IRSbIsZELFB6sqcyRj7HhMoWMkdEyPb2f8mq61MzTgE6lJGIyTRvEoFie7 -qtGADIofAgMBAAECggEBAJ47X3y2xaU7f0KQHsVafgI2JAnuDl+zusOOhJlJs8Wl -0Sc1EgjjAxOQiqcaE96rap//qqYDTuFLjCenkuItV32KNzizr3+GLZWaruRHS6X4 -xpFG2/gUrsQL3fdudOxpP+01lmzW+f25xRvZ4VilWRabquSDntWxA0R3cOwKFbGD -uuwbTw3pBrRfCk/2IdpQtRrvvkVIFiYT6b/zeCQzhp4RETbC0oxqcEEOIUGmimAV -9cbwafinxCo54cOfX4JAh3j7Mp3eQUymoFk5gnmIeVe0QmpH2VkN7eItrhEvHKOk -On7a5xvQ8s3wqPV5ZawHQcqar/p3QnGkiT6a+8LkIMECgYEA2iJ2DprTGZFRN0M7 -Yj4WLsSC3/GKK8eYsKG3TvMrmPqUDaiWLIvBoc1Le59x9eoF7Mha+WX+cAFL+GTg -1sB+PUZZStpf1R1tGvMldvpQ+5GplUBpuQe4J0n5rCG6+5jkvSr7xO+G1B+C3GFq -KR3iltiW5WJRVwh2k8yGvx3agyUCgYEAwsKFX82F7O+9IVud1JSQWmZMiyEK+DEX -JRnwx4HBuWr+AZqbb0grRRb6x8JTUOD4T7DZGxTaAdfzzRjKU2sBAO8VCgaj2Auv -5nsbvfXvrmDDCqwoaD2PMy+kgFvE0QTh65tzuGXl1IgpIYSC1JwnP6kOeUDbqE+k -UXzfVZzDdvMCgYByk9dfJIPt0h7O4Em4+NO+DQqRhtYE2PqjDM60cZZc7IIICp2X -GHHFA4i6jq3Vde9WyIbAqYpUWtoExzgylTm6BdGxN7NOxf4hQcZUEHepLIHfG85s -mlloibrTZ4RH06+SjZlhgE9Z7JNYHvMcVc5HXc0k/9ep15AxYiUFDjFQ4QKBgG7i -k089U4/X2wWgBNdgkmN1tQTNllJCmNvdzhG41dQ8j0vYe8C7BS+76qJLCGaW/6lX -lfRuRcUg78UI5UDjPloKxR7FMwmxdb+yvdPEr2bH3qQ36nWW/u30pSMTnJYownwD -MLp/AYCk2U4lBNwJ3+rF1ODCRY2pcnOWtg0nSL5zAoGAWRoOinogEnOodJzO7eB3 -TmL6M9QMyrAPBDsCnduJ8yW5mMUNod139YbSDxZPYwTLhK/GiHP/7OvLV5hg0s4s -QKnNaMeEowX7dyEO4ehnbfzysxXPKLRVhWhN6MCUc71NMxqr7QkuCXAjJS6/G21+ -Im3+Xb3Scq+UZghR+jiEZF0= ------END PRIVATE KEY----- diff --git a/examples/pki/private/signing_key.pem b/examples/pki/private/signing_key.pem deleted file mode 100644 index 758c0ffe..00000000 --- a/examples/pki/private/signing_key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDM+VrILLl962VH -S8EKWVzdkaOy0OoxGZ63gajM7VTm8AbgtVnYibIOnVZQuz1XbftIGNXPFhYNUypr -LnMXrEEsnxgD4PvU/4bETG+stdricX6d1oKqsNFNR7F7zImiR/OzGhp7dONwccxf -kfX4QHA5Ogso+XMfSdC72SRDszeCeGUcjuo/w2WSLW95SuVvcZLqE/pk3Q2TkCZ1 -8hvNfLoln43QpC469a7srUXATqOJ2mPNvL6E/wOyPefmAoCoG44lFoR3k2jZjBEI -hstJxmH7XgvqErBzpcWd29dms8xz5PNwYdns9CIfb3GaHvQ6r5RTl37/avDrGHOW -KOoD01xLAgMBAAECggEAaIi22qWsh+JYCW9B6NRAPyN6V8Sh2x6UykOO4cwb45b/ -+vOh+YPn0fo9vfhvxTnq0A8SY4WBA5SpanYK7kTEDEyqw7em1y7l/RB6V5t7IMb+ -6uIuS3zXkVEB3AApJSEK0Ql7/gBTydHPh+H5jnzWfujyLhhhtNBBarvH+drZcWio -lWx8RERN4cH+3DZD/xxjH2Ff+X1XMvb8Xcup7MlWi2FtREg7LttLNWNK25iWjciP -QwfWQIrURRJrD2IrOr9V2nuIEvRqRRBoO+pxJT2sC48NJ3hiKV2GtSQe2nRpQJ47 -f9MEsF5KVQOOn+aQ60EKOI0MpNPmpiCZ5hFvBrNuOQKBgQD6vueEdI9eJgz5YN+t -XWdpNippv35RTD8R4bQcE6GqIUXOmtQFS2wPJLn7nisZUsGMNEs36Yl0T9iow63r -5GNAfgzpqN1XZqaSMwAdxKmlBNYpAkVXHhv+1jN+9diDYmoj9T+3Q6Zvk5e/Liyp -6i+TsDppwmmr2utWajhyJ7owFwKBgQDRROncTztGDYLfRcrIoYsPo79KQ8tqwd2a -07Usch2kplTqojCUmmhMMFgV2eZPPiCjnEy2bAYh9I/oj7xG6EwApXTshZdCpivC -rbUV64MakRTUP8IvM6PdI+apkJRsRUi/bSyIbcRlvEoCMNZhfj/5VY6w/jlwrPJj -oBOCXBlB7QKBgQDGEbEeX1i03UfYYh6uep7qbEAaooqsu5cCkBDPMO6+TmQvLPyY -Zhio6bEEQs/2w/lhwBk+xHqw5zXVMiWbtiB03F1k4eBeXxbrW+AWo7gCQ4zMfh+6 -Dm284wVwn9D1D/OaDevT31uEvcjb2ySq3/PPLSEnU8xXVaoa6/NEsX8Q5wKBgQCm -2smULWBXZKJ6n00mVxdnqun0rsVcI6Mrta14+KwGAdEnG5achdivFsTE924YtLKV -gSPxN4RUQokTprc52jHvOf1WMNYAADpYCOSfy55G6nKvIP8VX5lB00Qw4uRUx5FP -gB7H0K2NaGmiAYqNRXqAtOUG3kyyOFMzeAjWIdTJqQKBgQCHzY1c7sS1vv7mPEkr -6CpwoaEbZeFnWoHBA8Rd82psqfYsVJIRwk5Id8zgDSEmoEi8hQ9UrYbrFpLK77xq -EYSxLQHTNlM0G3lyEsv/gJhwYYhdTYiW3Cx3F6Y++jyn9O/+hFMyQvuesAL7DUYE -ptEfvzFprpQUpByXkIpuJub6fg== ------END PRIVATE KEY----- diff --git a/examples/pki/private/ssl_key.pem b/examples/pki/private/ssl_key.pem deleted file mode 100644 index 363ce94b..00000000 --- a/examples/pki/private/ssl_key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL06AaJROwHPgJ -9tcySSBepzJ81jYars2sMvLjyuvdiIBbhWvbS/a9Tw3WgL8H6OALkHiOU/f0A6Rp -v8dGDIDsxZQVjT/4SLaQUOeDM+9bfkKHpSd9G3CsdSSZgOH08n+MyZ7slPHfUHLY -Wso0SJD0vAi1gmGDlSM/mmhhHTpCDGo6Wbwqare6JNeTCGJTJYwrxtoMCh/W1Zrs -lPC5lFvlHD7KBBf6IU2A8Xh/dUa3p5pmQeHPW8Em90DzIB1qH0DRXl3KANc24xYR -R45pPCVkk6vFsy6P0JwwpnkszB+LcK6CEsJhLsOYvQFsiQfSZ8m7YGhgrMLxtop4 -YEPirGGrAgMBAAECggEATwvbY0hNwlb5uqOIAXBqpUqiQdexU9fG26lGmSDxKBDv -9o5frcRgBDrMWwvDCgY+HT4CAvB9kJx4/qnpVjkzJp/ZNiJ5VIiehIlbv348rXbh -xkk+bz5dDATCFOXuu1fwL2FhyM5anwhMAav0DyK1VLQ3jGzr9GO6L8hqAn+bQFFu -6ngiODwfhBMl5aRoL9UOBEhccK07znrH0JGRz+3+5Cdz59Xw91Bv210LhNNDL58+ -0JD0N+YztVOQd2bgwo0bQbOEijzmYq+0mjoqAnJh1/++y7PlIPs0AnPgqSnFPx9+ -6FsQEVRgk5Uq3kvPLaP4nT2y6MDZSp+ujYldvJhyQQKBgQDuX2pZIJMZ4aFnkG+K -TmJ5wsLa/u9an0TmvAL9RLtBpVpQNKD8cQ+y8PUZavXDbAIt5NWqZVnTbCR79Dnd -mZKblwcHhtsyA5f89el5KcxY2BREWdHdTnJpNd7XRlUECmzvX1zGj77lA982PhII -yflRBRV3vqLkgC8vfoYgRyRElwKBgQDa5jnLdx/RahfYMOgn1HE5o4hMzLR4Y0Dd -+gELshcUbPqouoP5zOb8WOagVJIgZVOSN+/VqbilVYrqRiNTn2rnoxs+HHRdaJNN -3eXllD4J2HfC2BIj1xSpIdyh2XewAJqw9IToHNB29QUhxOtgwseHciPG6JaKH2ik -kqGKH/EKDQKBgFFAftygiOPCkCTgC9UmANUmOQsy6N2H+pF3tsEj43xt44oBVnqW -A1boYXNnjRwuvdNs9BPf9i1l6E3EItFRXrLgWQoMwryakv0ryYh+YeRKyyW9RBbe -fYs1TJ8unx4Ae79gTxxztQsVNcmkgLs0NWKTjAzEE3w14V+cDhYEie1DAoGBAJdI -V5cLrBzBstsB6eBlDR9lqrRRIUS2a8U9m+1mVlcSfiWQSdehSd4K3tDdwePLw3ch -W4qR8n+pYAlLEe0gFvUhn5lMdwt7U5qUCeehjUKmrRYm2FqWsbu2IFJnBjXIJSC4 -zQXRrC0aZ0KQYpAL7XPpaVp1slyhGmPqxuO78Y0dAoGBAMHo3EIMwu9rfuGwFodr -GFsOZhfJqgo5GDNxxf89Q9WWpMDTCdX+wdBTrN/wsMbBuwIDHrUuRnk6D5CWRjSk -/ikCgHN3kOtrbL8zzqRomGAIIWKYGFEIGe1GHVGo5r//HXHdPxFXygvruQ/xbOA4 -RGvmDiji8vVDq7Shho8I6KuT ------END PRIVATE KEY----- diff --git a/examples/pki/run_all.sh b/examples/pki/run_all.sh deleted file mode 100755 index 2438ec7c..00000000 --- a/examples/pki/run_all.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -x - -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script generates the crypto necessary for the SSL tests. - -. gen_pki.sh - -check_openssl -rm_old -cleanup -setup -generate_ca -ssl_cert_req -cms_signing_cert_req -issue_certs -gen_sample_cms -cleanup diff --git a/keystoneclient/__init__.py b/keystoneclient/__init__.py deleted file mode 100644 index e8ef58eb..00000000 --- a/keystoneclient/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""The python bindings for the OpenStack Identity (Keystone) project. - -A Client object will allow you to communicate with the Identity server. The -recommended way to get a Client object is to use -:py:func:`keystoneclient.client.Client()`. :py:func:`~.Client()` uses version -discovery to create a V3 or V2 client depending on what versions the Identity -server supports and what version is requested. - -Identity V2 and V3 clients can also be created directly. See -:py:class:`keystoneclient.v3.client.Client` for the V3 client and -:py:class:`keystoneclient.v2_0.client.Client` for the V2 client. - -""" - -import importlib -import sys - -import pbr.version - - -__version__ = pbr.version.VersionInfo('python-keystoneclient').version_string() - -__all__ = ( - # Modules - 'generic', - 'v2_0', - 'v3', - - # Packages - 'access', - 'client', - 'exceptions', - 'httpclient', - 'service_catalog', -) - - -class _LazyImporter(object): - def __init__(self, module): - self._module = module - - def __getattr__(self, name): - # NB: this is only called until the import has been done. - # These submodules are part of the API without explicit importing, but - # expensive to load, so we load them on-demand rather than up-front. - lazy_submodules = [ - 'access', - 'client', - 'exceptions', - 'generic', - 'httpclient', - 'service_catalog', - 'v2_0', - 'v3', - ] - if name in lazy_submodules: - return importlib.import_module('keystoneclient.%s' % name) - - # Return module attributes like __all__ etc. - return getattr(self._module, name) - - -sys.modules[__name__] = _LazyImporter(sys.modules[__name__]) diff --git a/keystoneclient/_discover.py b/keystoneclient/_discover.py deleted file mode 100644 index 69eed9a9..00000000 --- a/keystoneclient/_discover.py +++ /dev/null @@ -1,333 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""The passive components to version discovery. - -The Discover object in discover.py contains functions that can create objects -on your behalf. These functions are not usable from within the keystoneclient -library because you will get dependency resolution issues. - -The Discover object in this file provides the querying components of Discovery. -This includes functions like url_for which allow you to retrieve URLs and the -raw data specified in version discovery responses. -""" - -import logging -import re - -from positional import positional - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -_LOGGER = logging.getLogger(__name__) - - -@positional() -def get_version_data(session, url, authenticated=None): - """Retrieve raw version data from a url.""" - headers = {'Accept': 'application/json'} - - resp = session.get(url, headers=headers, authenticated=authenticated) - - try: - body_resp = resp.json() - except ValueError: # nosec(cjschaef): raise a DiscoveryFailure below - pass - else: - # In the event of querying a root URL we will get back a list of - # available versions. - try: - return body_resp['versions']['values'] - except (KeyError, TypeError): # nosec(cjschaef): attempt to return - # versions dict or query the endpoint or raise a DiscoveryFailure - pass - - # Most servers don't have a 'values' element so accept a simple - # versions dict if available. - try: - return body_resp['versions'] - except KeyError: # nosec(cjschaef): query the endpoint or raise a - # DiscoveryFailure - pass - - # Otherwise if we query an endpoint like /v2.0 then we will get back - # just the one available version. - try: - return [body_resp['version']] - except KeyError: # nosec(cjschaef): raise a DiscoveryFailure - pass - - err_text = resp.text[:50] + '...' if len(resp.text) > 50 else resp.text - msg = _('Invalid Response - Bad version data returned: %s') % err_text - raise exceptions.DiscoveryFailure(msg) - - -def normalize_version_number(version): - """Turn a version representation into a tuple.""" - # trim the v from a 'v2.0' or similar - try: - version = version.lstrip('v') - except AttributeError: # nosec(cjschaef): 'version' is not a str, try a - # different type or raise a TypeError - pass - - # if it's an integer or a numeric as a string then normalize it - # to a string, this ensures 1 decimal point - try: - num = float(version) - except Exception: # nosec(cjschaef): 'version' is not a float, try a - # different type or raise a TypeError - pass - else: - version = str(num) - - # if it's a string (or an integer) from above break it on . - try: - return tuple(map(int, version.split('.'))) - except Exception: # nosec(cjschaef): 'version' is not str (or an int), - # try a different type or raise a TypeError - pass - - # last attempt, maybe it's a list or iterable. - try: - return tuple(map(int, version)) - except Exception: # nosec(cjschaef): 'version' is not an expected type, - # raise a TypeError - pass - - raise TypeError(_('Invalid version specified: %s') % version) - - -def version_match(required, candidate): - """Test that an available version satisfies the required version. - - To be suitable a version must be of the same major version as required - and be at least a match in minor/patch level. - - eg. 3.3 is a match for a required 3.1 but 4.1 is not. - - :param tuple required: the version that must be met. - :param tuple candidate: the version to test against required. - - :returns: True if candidate is suitable False otherwise. - :rtype: bool - """ - # major versions must be the same (e.g. even though v2 is a lower - # version than v3 we can't use it if v2 was requested) - if candidate[0] != required[0]: - return False - - # prevent selecting a minor version less than what is required - if candidate < required: - return False - - return True - - -class Discover(object): - - CURRENT_STATUSES = ('stable', 'current', 'supported') - DEPRECATED_STATUSES = ('deprecated',) - EXPERIMENTAL_STATUSES = ('experimental',) - - @positional() - def __init__(self, session, url, authenticated=None): - self._data = get_version_data(session, url, - authenticated=authenticated) - - def raw_version_data(self, allow_experimental=False, - allow_deprecated=True, allow_unknown=False): - """Get raw version information from URL. - - Raw data indicates that only minimal validation processing is performed - on the data, so what is returned here will be the data in the same - format it was received from the endpoint. - - :param bool allow_experimental: Allow experimental version endpoints. - :param bool allow_deprecated: Allow deprecated version endpoints. - :param bool allow_unknown: Allow endpoints with an unrecognised status. - - :returns: The endpoints returned from the server that match the - criteria. - :rtype: list - """ - versions = [] - for v in self._data: - try: - status = v['status'] - except KeyError: - _LOGGER.warning('Skipping over invalid version data. ' - 'No stability status in version.') - continue - - status = status.lower() - - if status in self.CURRENT_STATUSES: - versions.append(v) - elif status in self.DEPRECATED_STATUSES: - if allow_deprecated: - versions.append(v) - elif status in self.EXPERIMENTAL_STATUSES: - if allow_experimental: - versions.append(v) - elif allow_unknown: - versions.append(v) - - return versions - - def version_data(self, **kwargs): - """Get normalized version data. - - Return version data in a structured way. - - :returns: A list of version data dictionaries sorted by version number. - Each data element in the returned list is a dictionary - consisting of at least: - - :version tuple: The normalized version of the endpoint. - :url str: The url for the endpoint. - :raw_status str: The status as provided by the server - :rtype: list(dict) - """ - if kwargs.pop('unstable', None): - kwargs.setdefault('allow_experimental', True) - kwargs.setdefault('allow_unknown', True) - data = self.raw_version_data(**kwargs) - versions = [] - - for v in data: - try: - version_str = v['id'] - except KeyError: - _LOGGER.info('Skipping invalid version data. Missing ID.') - continue - - try: - links = v['links'] - except KeyError: - _LOGGER.info('Skipping invalid version data. Missing links') - continue - - version_number = normalize_version_number(version_str) - - for link in links: - try: - rel = link['rel'] - url = link['href'] - except (KeyError, TypeError): - _LOGGER.info('Skipping invalid version link. ' - 'Missing link URL or relationship.') - continue - - if rel.lower() == 'self': - break - else: - _LOGGER.info('Skipping invalid version data. ' - 'Missing link to endpoint.') - continue - - versions.append({'version': version_number, - 'url': url, - 'raw_status': v['status']}) - - versions.sort(key=lambda v: v['version']) - return versions - - def data_for(self, version, **kwargs): - """Return endpoint data for a version. - - :param tuple version: The version is always a minimum version in the - same major release as there should be no compatibility issues with - using a version newer than the one asked for. - - :returns: the endpoint data for a URL that matches the required version - (the format is described in version_data) or None if no - match. - :rtype: dict - """ - version = normalize_version_number(version) - version_data = self.version_data(**kwargs) - - for data in reversed(version_data): - if version_match(version, data['version']): - return data - - return None - - def url_for(self, version, **kwargs): - """Get the endpoint url for a version. - - :param tuple version: The version is always a minimum version in the - same major release as there should be no compatibility issues with - using a version newer than the one asked for. - - :returns: The url for the specified version or None if no match. - :rtype: str - """ - data = self.data_for(version, **kwargs) - return data['url'] if data else None - - -class _VersionHacks(object): - """A container to abstract the list of version hacks. - - This could be done as simply a dictionary but is abstracted like this to - make for easier testing. - """ - - def __init__(self): - self._discovery_data = {} - - def add_discover_hack(self, service_type, old, new=''): - """Add a new hack for a service type. - - :param str service_type: The service_type in the catalog. - :param re.RegexObject old: The pattern to use. - :param str new: What to replace the pattern with. - """ - hacks = self._discovery_data.setdefault(service_type, []) - hacks.append((old, new)) - - def get_discover_hack(self, service_type, url): - """Apply the catalog hacks and figure out an unversioned endpoint. - - :param str service_type: the service_type to look up. - :param str url: The original url that came from a service_catalog. - - :returns: Either the unversioned url or the one from the catalog - to try. - """ - for old, new in self._discovery_data.get(service_type, []): - new_string, number_of_subs_made = old.subn(new, url) - if number_of_subs_made > 0: - return new_string - - return url - - -_VERSION_HACKS = _VersionHacks() -_VERSION_HACKS.add_discover_hack('identity', re.compile('/v2.0/?$'), '/') - - -def get_catalog_discover_hack(service_type, url): - """Apply the catalog hacks and figure out an unversioned endpoint. - - This function is internal to keystoneclient. - - :param str service_type: the service_type to look up. - :param str url: The original url that came from a service_catalog. - - :returns: Either the unversioned url or the one from the catalog to try. - """ - return _VERSION_HACKS.get_discover_hack(service_type, url) diff --git a/keystoneclient/access.py b/keystoneclient/access.py deleted file mode 100644 index f8174f61..00000000 --- a/keystoneclient/access.py +++ /dev/null @@ -1,886 +0,0 @@ -# Copyright 2012 Nebula, Inc. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import datetime -import warnings - -from oslo_utils import timeutils - -from keystoneclient.i18n import _ -from keystoneclient import service_catalog - - -# gap, in seconds, to determine whether the given token is about to expire -STALE_TOKEN_DURATION = 30 - - -class AccessInfo(dict): - """Encapsulates a raw authentication token from keystone. - - Provides helper methods for extracting useful values from that token. - - """ - - @classmethod - def factory(cls, resp=None, body=None, region_name=None, auth_token=None, - **kwargs): - """Factory function to create a new AccessInfo object. - - Create AccessInfo object given a successful auth response & body - or a user-provided dict. - - .. warning:: - - Use of the region_name argument is deprecated as of the 1.7.0 - release and may be removed in the 2.0.0 release. - - """ - if region_name: - warnings.warn( - 'Use of the region_name argument is deprecated as of the ' - '1.7.0 release and may be removed in the 2.0.0 release.', - DeprecationWarning) - - if body is not None or len(kwargs): - if AccessInfoV3.is_valid(body, **kwargs): - if resp and not auth_token: - auth_token = resp.headers['X-Subject-Token'] - # NOTE(jamielennox): these return AccessInfo because they - # already have auth_token installed on them. - if body: - if region_name: - body['token']['region_name'] = region_name - return AccessInfoV3(auth_token, **body['token']) - else: - return AccessInfoV3(auth_token, **kwargs) - elif AccessInfoV2.is_valid(body, **kwargs): - if body: - if region_name: - body['access']['region_name'] = region_name - auth_ref = AccessInfoV2(**body['access']) - else: - auth_ref = AccessInfoV2(**kwargs) - else: - raise NotImplementedError(_('Unrecognized auth response')) - else: - auth_ref = AccessInfoV2(**kwargs) - - if auth_token: - auth_ref.auth_token = auth_token - - return auth_ref - - def __init__(self, *args, **kwargs): - super(AccessInfo, self).__init__(*args, **kwargs) - self.service_catalog = service_catalog.ServiceCatalog.factory( - resource_dict=self, region_name=self._region_name) - - @property - def _region_name(self): - return self.get('region_name') - - def will_expire_soon(self, stale_duration=None): - """Determine if expiration is about to occur. - - :returns: true if expiration is within the given duration - :rtype: boolean - - """ - stale_duration = (STALE_TOKEN_DURATION if stale_duration is None - else stale_duration) - norm_expires = timeutils.normalize_time(self.expires) - # (gyee) should we move auth_token.will_expire_soon() to timeutils - # instead of duplicating code here? - soon = (timeutils.utcnow() + datetime.timedelta( - seconds=stale_duration)) - return norm_expires < soon - - @classmethod - def is_valid(cls, body, **kwargs): - """Determine if processing valid v2 or v3 token. - - Validates from the auth body or a user-provided dict. - - :returns: true if auth body matches implementing class - :rtype: boolean - """ - raise NotImplementedError() - - def has_service_catalog(self): - """Return true if the authorization token has a service catalog. - - :returns: boolean - """ - raise NotImplementedError() - - @property - def auth_token(self): - """Return the token_id associated with the auth request. - - To be used in headers for authenticating OpenStack API requests. - - :returns: str - """ - return self['auth_token'] - - @auth_token.setter - def auth_token(self, value): - self['auth_token'] = value - - @auth_token.deleter - def auth_token(self): - try: - del self['auth_token'] - except KeyError: # nosec(cjschaef): 'auth_token' is not in the dict - pass - - @property - def expires(self): - """Return the token expiration (as datetime object). - - :returns: datetime - """ - raise NotImplementedError() - - @property - def issued(self): - """Return the token issue time (as datetime object). - - :returns: datetime - """ - raise NotImplementedError() - - @property - def username(self): - """Return the username associated with the auth request. - - Follows the pattern defined in the V2 API of first looking for 'name', - returning that if available, and falling back to 'username' if name - is unavailable. - - :returns: str - """ - raise NotImplementedError() - - @property - def user_id(self): - """Return the user id associated with the auth request. - - :returns: str - """ - raise NotImplementedError() - - @property - def user_domain_id(self): - """Return the user's domain id associated with the auth request. - - For v2, it always returns 'default' which may be different from the - Keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def user_domain_name(self): - """Return the user's domain name associated with the auth request. - - For v2, it always returns 'Default' which may be different from the - Keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def role_ids(self): - """Return a list of user's role ids associated with the auth request. - - :returns: a list of strings of role ids - """ - raise NotImplementedError() - - @property - def role_names(self): - """Return a list of user's role names associated with the auth request. - - :returns: a list of strings of role names - """ - raise NotImplementedError() - - @property - def domain_name(self): - """Return the domain name associated with the auth request. - - :returns: str or None (if no domain associated with the token) - """ - raise NotImplementedError() - - @property - def domain_id(self): - """Return the domain id associated with the auth request. - - :returns: str or None (if no domain associated with the token) - """ - raise NotImplementedError() - - @property - def project_name(self): - """Return the project name associated with the auth request. - - :returns: str or None (if no project associated with the token) - """ - raise NotImplementedError() - - @property - def tenant_name(self): - """Synonym for project_name.""" - return self.project_name - - @property - def scoped(self): - """Return true if the auth token was scoped. - - Return true if scoped to a tenant(project) or domain, - and contains a populated service catalog. - - .. warning:: - - This is deprecated as of the 1.7.0 release in favor of - project_scoped and may be removed in the 2.0.0 release. - - :returns: bool - """ - raise NotImplementedError() - - @property - def project_scoped(self): - """Return true if the auth token was scoped to a tenant(project). - - :returns: bool - """ - raise NotImplementedError() - - @property - def domain_scoped(self): - """Return true if the auth token was scoped to a domain. - - :returns: bool - """ - raise NotImplementedError() - - @property - def trust_id(self): - """Return the trust id associated with the auth request. - - :returns: str or None (if no trust associated with the token) - """ - raise NotImplementedError() - - @property - def trust_scoped(self): - """Return true if the auth token was scoped from a delegated trust. - - The trust delegation is via the OS-TRUST v3 extension. - - :returns: bool - """ - raise NotImplementedError() - - @property - def trustee_user_id(self): - """Return the trustee user id associated with a trust. - - :returns: str or None (if no trust associated with the token) - """ - raise NotImplementedError() - - @property - def trustor_user_id(self): - """Return the trustor user id associated with a trust. - - :returns: str or None (if no trust associated with the token) - """ - raise NotImplementedError() - - @property - def project_id(self): - """Return the project ID associated with the auth request. - - This returns None if the auth token wasn't scoped to a project. - - :returns: str or None (if no project associated with the token) - """ - raise NotImplementedError() - - @property - def tenant_id(self): - """Synonym for project_id.""" - return self.project_id - - @property - def project_domain_id(self): - """Return the project's domain id associated with the auth request. - - For v2, it returns 'default' if a project is scoped or None which may - be different from the keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def project_domain_name(self): - """Return the project's domain name associated with the auth request. - - For v2, it returns 'Default' if a project is scoped or None which may - be different from the keystone configuration. - - :returns: str - """ - raise NotImplementedError() - - @property - def auth_url(self): - """Return a tuple of identity URLs. - - The identity URLs are from publicURL and adminURL for the service - 'identity' from the service catalog associated with the authorization - request. If the authentication request wasn't scoped to a tenant - (project), this property will return None. - - DEPRECATED: this doesn't correctly handle region name. You should fetch - it from the service catalog yourself. This may be removed in the 2.0.0 - release. - - :returns: tuple of urls - """ - raise NotImplementedError() - - @property - def management_url(self): - """Return the first adminURL of the identity endpoint. - - The identity endpoint is from the service catalog - associated with the authorization request, or None if the - authentication request wasn't scoped to a tenant (project). - - DEPRECATED: this doesn't correctly handle region name. You should fetch - it from the service catalog yourself. This may be removed in the 2.0.0 - release. - - :returns: tuple of urls - """ - raise NotImplementedError() - - @property - def version(self): - """Return the version of the auth token from identity service. - - :returns: str - """ - return self.get('version') - - @property - def oauth_access_token_id(self): - """Return the access token ID if OAuth authentication used. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def oauth_consumer_id(self): - """Return the consumer ID if OAuth authentication used. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def is_federated(self): - """Return true if federation was used to get the token. - - :returns: boolean - """ - raise NotImplementedError() - - @property - def audit_id(self): - """Return the audit ID if present. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def audit_chain_id(self): - """Return the audit chain ID if present. - - In the event that a token was rescoped then this ID will be the - :py:attr:`audit_id` of the initial token. Returns None if no value - present. - - :returns: str or None. - """ - raise NotImplementedError() - - @property - def initial_audit_id(self): - """The audit ID of the initially requested token. - - This is the :py:attr:`audit_chain_id` if present or the - :py:attr:`audit_id`. - """ - return self.audit_chain_id or self.audit_id - - -class AccessInfoV2(AccessInfo): - """An object for encapsulating raw v2 auth token from identity service.""" - - def __init__(self, *args, **kwargs): - super(AccessInfo, self).__init__(*args, **kwargs) - self.update(version='v2.0') - self.service_catalog = service_catalog.ServiceCatalog.factory( - resource_dict=self, - token=self['token']['id'], - region_name=self._region_name) - - @classmethod - def is_valid(cls, body, **kwargs): - if body: - return 'access' in body - elif kwargs: - return kwargs.get('version') == 'v2.0' - else: - return False - - def has_service_catalog(self): - return 'serviceCatalog' in self - - @AccessInfo.auth_token.getter - def auth_token(self): - try: - return super(AccessInfoV2, self).auth_token - except KeyError: - return self['token']['id'] - - @property - def expires(self): - return timeutils.parse_isotime(self['token']['expires']) - - @property - def issued(self): - return timeutils.parse_isotime(self['token']['issued_at']) - - @property - def username(self): - return self['user'].get('name', self['user'].get('username')) - - @property - def user_id(self): - return self['user']['id'] - - @property - def user_domain_id(self): - return 'default' - - @property - def user_domain_name(self): - return 'Default' - - @property - def role_ids(self): - return self.get('metadata', {}).get('roles', []) - - @property - def role_names(self): - return [r['name'] for r in self['user'].get('roles', [])] - - @property - def domain_name(self): - return None - - @property - def domain_id(self): - return None - - @property - def project_name(self): - try: - tenant_dict = self['token']['tenant'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenant' key in - # token, return the name of the tenant or None - pass - else: - return tenant_dict.get('name') - - # pre grizzly - try: - return self['user']['tenantName'] - except KeyError: # nosec(cjschaef): no 'user' key or 'tenantName' in - # 'user', attempt 'tenantId' or return None - pass - - # pre diablo, keystone only provided a tenantId - try: - return self['token']['tenantId'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenantName' or - # 'tenantId' could be found, return None - pass - - @property - def scoped(self): - """Deprecated as of the 1.7.0 release. - - Use project_scoped instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'scoped is deprecated as of the 1.7.0 release in favor of ' - 'project_scoped and may be removed in the 2.0.0 release.', - DeprecationWarning) - if ('serviceCatalog' in self - and self['serviceCatalog'] - and 'tenant' in self['token']): - return True - return False - - @property - def project_scoped(self): - return 'tenant' in self['token'] - - @property - def domain_scoped(self): - return False - - @property - def trust_id(self): - return self.get('trust', {}).get('id') - - @property - def trust_scoped(self): - return 'trust' in self - - @property - def trustee_user_id(self): - return self.get('trust', {}).get('trustee_user_id') - - @property - def trustor_user_id(self): - # this information is not available in the v2 token bug: #1331882 - return None - - @property - def project_id(self): - try: - tenant_dict = self['token']['tenant'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenant' dict, - # attempt to return 'tenantId' or return None - pass - else: - return tenant_dict.get('id') - - # pre grizzly - try: - return self['user']['tenantId'] - except KeyError: # nosec(cjschaef): no 'user' key or 'tenantId' in - # 'user', attempt to retrieve from 'token' or return None - pass - - # pre diablo - try: - return self['token']['tenantId'] - except KeyError: # nosec(cjschaef): no 'token' key or 'tenantId' - # could be found, return None - pass - - @property - def project_domain_id(self): - if self.project_id: - return 'default' - - @property - def project_domain_name(self): - if self.project_id: - return 'Default' - - @property - def auth_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'auth_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='publicURL', - region_name=self._region_name) - else: - return None - - @property - def management_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'management_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='adminURL', - region_name=self._region_name) - else: - return None - - @property - def oauth_access_token_id(self): - return None - - @property - def oauth_consumer_id(self): - return None - - @property - def is_federated(self): - return False - - @property - def audit_id(self): - try: - return self['token'].get('audit_ids', [])[0] - except IndexError: - return None - - @property - def audit_chain_id(self): - try: - return self['token'].get('audit_ids', [])[1] - except IndexError: - return None - - -class AccessInfoV3(AccessInfo): - """An object encapsulating raw v3 auth token from identity service.""" - - def __init__(self, token, *args, **kwargs): - super(AccessInfo, self).__init__(*args, **kwargs) - self.update(version='v3') - self.service_catalog = service_catalog.ServiceCatalog.factory( - resource_dict=self, - token=token, - region_name=self._region_name) - if token: - self.auth_token = token - - @classmethod - def is_valid(cls, body, **kwargs): - if body: - return 'token' in body - elif kwargs: - return kwargs.get('version') == 'v3' - else: - return False - - def has_service_catalog(self): - return 'catalog' in self - - @property - def is_federated(self): - return 'OS-FEDERATION' in self['user'] - - @property - def expires(self): - return timeutils.parse_isotime(self['expires_at']) - - @property - def issued(self): - return timeutils.parse_isotime(self['issued_at']) - - @property - def user_id(self): - return self['user']['id'] - - @property - def user_domain_id(self): - try: - return self['user']['domain']['id'] - except KeyError: - if self.is_federated: - return None - raise - - @property - def user_domain_name(self): - try: - return self['user']['domain']['name'] - except KeyError: - if self.is_federated: - return None - raise - - @property - def role_ids(self): - return [r['id'] for r in self.get('roles', [])] - - @property - def role_names(self): - return [r['name'] for r in self.get('roles', [])] - - @property - def username(self): - return self['user']['name'] - - @property - def domain_name(self): - domain = self.get('domain') - if domain: - return domain['name'] - - @property - def domain_id(self): - domain = self.get('domain') - if domain: - return domain['id'] - - @property - def project_id(self): - project = self.get('project') - if project: - return project['id'] - - @property - def project_domain_id(self): - project = self.get('project') - if project: - return project['domain']['id'] - - @property - def project_domain_name(self): - project = self.get('project') - if project: - return project['domain']['name'] - - @property - def project_name(self): - project = self.get('project') - if project: - return project['name'] - - @property - def scoped(self): - """Deprecated as of the 1.7.0 release. - - Use project_scoped instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'scoped is deprecated as of the 1.7.0 release in favor of ' - 'project_scoped and may be removed in the 2.0.0 release.', - DeprecationWarning) - return ('catalog' in self and self['catalog'] and 'project' in self) - - @property - def project_scoped(self): - return 'project' in self - - @property - def domain_scoped(self): - return 'domain' in self - - @property - def trust_id(self): - return self.get('OS-TRUST:trust', {}).get('id') - - @property - def trust_scoped(self): - return 'OS-TRUST:trust' in self - - @property - def trustee_user_id(self): - return self.get('OS-TRUST:trust', {}).get('trustee_user', {}).get('id') - - @property - def trustor_user_id(self): - return self.get('OS-TRUST:trust', {}).get('trustor_user', {}).get('id') - - @property - def auth_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'auth_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='public', - region_name=self._region_name) - else: - return None - - @property - def management_url(self): - """Deprecated as of the 1.7.0 release. - - Use service_catalog.get_urls() instead. It may be removed in the - 2.0.0 release. - """ - warnings.warn( - 'management_url is deprecated as of the 1.7.0 release in favor of ' - 'service_catalog.get_urls() and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - if self.service_catalog: - return self.service_catalog.get_urls(service_type='identity', - endpoint_type='admin', - region_name=self._region_name) - - else: - return None - - @property - def oauth_access_token_id(self): - return self.get('OS-OAUTH1', {}).get('access_token_id') - - @property - def oauth_consumer_id(self): - return self.get('OS-OAUTH1', {}).get('consumer_id') - - @property - def audit_id(self): - try: - return self.get('audit_ids', [])[0] - except IndexError: - return None - - @property - def audit_chain_id(self): - try: - return self.get('audit_ids', [])[1] - except IndexError: - return None diff --git a/keystoneclient/adapter.py b/keystoneclient/adapter.py deleted file mode 100644 index faa61a69..00000000 --- a/keystoneclient/adapter.py +++ /dev/null @@ -1,223 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import warnings - -from oslo_serialization import jsonutils -from positional import positional - - -class Adapter(object): - """An instance of a session with local variables. - - A session is a global object that is shared around amongst many clients. It - therefore contains state that is relevant to everyone. There is a lot of - state such as the service type and region_name that are only relevant to a - particular client that is using the session. An adapter provides a wrapper - of client local data around the global session object. - - :param session: The session object to wrap. - :type session: keystoneclient.session.Session - :param str service_type: The default service_type for URL discovery. - :param str service_name: The default service_name for URL discovery. - :param str interface: The default interface for URL discovery. - :param str region_name: The default region_name for URL discovery. - :param str endpoint_override: Always use this endpoint URL for requests - for this client. - :param tuple version: The version that this API targets. - :param auth: An auth plugin to use instead of the session one. - :type auth: keystoneclient.auth.base.BaseAuthPlugin - :param str user_agent: The User-Agent string to set. - :param int connect_retries: the maximum number of retries that should - be attempted for connection errors. - Default None - use session default which - is don't retry. - :param logger: A logging object to use for requests that pass through this - adapter. - :type logger: logging.Logger - """ - - @positional() - def __init__(self, session, service_type=None, service_name=None, - interface=None, region_name=None, endpoint_override=None, - version=None, auth=None, user_agent=None, - connect_retries=None, logger=None): - warnings.warn( - 'keystoneclient.adapter.Adapter is deprecated as of the 2.1.0 ' - 'release in favor of keystoneauth1.adapter.Adapter. It will be ' - 'removed in future releases.', DeprecationWarning) - - # NOTE(jamielennox): when adding new parameters to adapter please also - # add them to the adapter call in httpclient.HTTPClient.__init__ - self.session = session - self.service_type = service_type - self.service_name = service_name - self.interface = interface - self.region_name = region_name - self.endpoint_override = endpoint_override - self.version = version - self.user_agent = user_agent - self.auth = auth - self.connect_retries = connect_retries - self.logger = logger - - def _set_endpoint_filter_kwargs(self, kwargs): - if self.service_type: - kwargs.setdefault('service_type', self.service_type) - if self.service_name: - kwargs.setdefault('service_name', self.service_name) - if self.interface: - kwargs.setdefault('interface', self.interface) - if self.region_name: - kwargs.setdefault('region_name', self.region_name) - if self.version: - kwargs.setdefault('version', self.version) - - def request(self, url, method, **kwargs): - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - self._set_endpoint_filter_kwargs(endpoint_filter) - - if self.endpoint_override: - kwargs.setdefault('endpoint_override', self.endpoint_override) - - if self.auth: - kwargs.setdefault('auth', self.auth) - if self.user_agent: - kwargs.setdefault('user_agent', self.user_agent) - if self.connect_retries is not None: - kwargs.setdefault('connect_retries', self.connect_retries) - if self.logger: - kwargs.setdefault('logger', self.logger) - - return self.session.request(url, method, **kwargs) - - def get_token(self, auth=None): - """Return a token as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: :class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - - :returns: A valid token. - :rtype: string - """ - return self.session.get_token(auth or self.auth) - - def get_endpoint(self, auth=None, **kwargs): - """Get an endpoint as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin on - the session. (optional) - :type auth: :class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - :returns: An endpoint if available or None. - :rtype: string - """ - if self.endpoint_override: - return self.endpoint_override - - self._set_endpoint_filter_kwargs(kwargs) - return self.session.get_endpoint(auth or self.auth, **kwargs) - - def invalidate(self, auth=None): - """Invalidate an authentication plugin.""" - return self.session.invalidate(auth or self.auth) - - def get_user_id(self, auth=None): - """Return the authenticated user_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns: Current `user_id` or None if not supported by plugin. - :rtype: string - """ - return self.session.get_user_id(auth or self.auth) - - def get_project_id(self, auth=None): - """Return the authenticated project_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns: Current `project_id` or None if not supported by plugin. - :rtype: string - """ - return self.session.get_project_id(auth or self.auth) - - def get(self, url, **kwargs): - return self.request(url, 'GET', **kwargs) - - def head(self, url, **kwargs): - return self.request(url, 'HEAD', **kwargs) - - def post(self, url, **kwargs): - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - return self.request(url, 'PUT', **kwargs) - - def patch(self, url, **kwargs): - return self.request(url, 'PATCH', **kwargs) - - def delete(self, url, **kwargs): - return self.request(url, 'DELETE', **kwargs) - - -class LegacyJsonAdapter(Adapter): - """Make something that looks like an old HTTPClient. - - A common case when using an adapter is that we want an interface similar to - the HTTPClients of old which returned the body as JSON as well. - - You probably don't want this if you are starting from scratch. - """ - - def request(self, *args, **kwargs): - headers = kwargs.setdefault('headers', {}) - headers.setdefault('Accept', 'application/json') - - try: - kwargs['json'] = kwargs.pop('body') - except KeyError: # nosec(cjschaef): kwargs doesn't contain a 'body' - # key, while 'json' is an optional argument for Session.request - pass - - resp = super(LegacyJsonAdapter, self).request(*args, **kwargs) - - body = None - if resp.text: - try: - body = jsonutils.loads(resp.text) - except ValueError: # nosec(cjschaef): return None for body as - # expected - pass - - return resp, body diff --git a/keystoneclient/auth/__init__.py b/keystoneclient/auth/__init__.py deleted file mode 100644 index eeae768f..00000000 --- a/keystoneclient/auth/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from keystoneclient.auth.base import * # noqa -from keystoneclient.auth.cli import * # noqa -from keystoneclient.auth.conf import * # noqa - - -__all__ = ( - # auth.base - 'AUTH_INTERFACE', - 'BaseAuthPlugin', - 'get_available_plugin_names', - 'get_available_plugin_classes', - 'get_plugin_class', - 'IDENTITY_AUTH_HEADER_NAME', - 'PLUGIN_NAMESPACE', - - # auth.cli - 'load_from_argparse_arguments', - 'register_argparse_arguments', - - # auth.conf - 'get_common_conf_options', - 'get_plugin_options', - 'load_from_conf_options', - 'register_conf_options', -) diff --git a/keystoneclient/auth/base.py b/keystoneclient/auth/base.py deleted file mode 100644 index 0036b8cf..00000000 --- a/keystoneclient/auth/base.py +++ /dev/null @@ -1,374 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from debtcollector import removals -from keystoneauth1 import plugin -import six -import stevedore - -from keystoneclient import exceptions - - -# NOTE(jamielennox): The AUTH_INTERFACE is a special value that can be -# requested from get_endpoint. If a plugin receives this as the value of -# 'interface' it should return the initial URL that was passed to the plugin. -AUTH_INTERFACE = plugin.AUTH_INTERFACE - -PLUGIN_NAMESPACE = 'keystoneclient.auth.plugin' -IDENTITY_AUTH_HEADER_NAME = 'X-Auth-Token' - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_available_plugin_names(): - """Get the names of all the plugins that are available on the system. - - This is particularly useful for help and error text to prompt a user for - example what plugins they may specify. - - :returns: A list of names. - :rtype: frozenset - """ - mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, - invoke_on_load=False) - return frozenset(mgr.names()) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_available_plugin_classes(): - """Retrieve all the plugin classes available on the system. - - :returns: A dict with plugin entrypoint name as the key and the plugin - class as the value. - :rtype: dict - """ - mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, - propagate_map_exceptions=True, - invoke_on_load=False) - - return dict(mgr.map(lambda ext: (ext.entry_point.name, ext.plugin))) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_plugin_class(name): - """Retrieve a plugin class by its entrypoint name. - - :param str name: The name of the object to get. - - :returns: An auth plugin class. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - try: - mgr = stevedore.DriverManager(namespace=PLUGIN_NAMESPACE, - name=name, - invoke_on_load=False) - except RuntimeError: - raise exceptions.NoMatchingPlugin(name) - - return mgr.driver - - -class BaseAuthPlugin(object): - """The basic structure of an authentication plugin.""" - - def get_token(self, session, **kwargs): - """Obtain a token. - - How the token is obtained is up to the plugin. If it is still valid - it may be re-used, retrieved from cache or invoke an authentication - request against a server. - - There are no required kwargs. They are passed directly to the auth - plugin and they are implementation specific. - - Returning None will indicate that no token was able to be retrieved. - - This function is misplaced as it should only be required for auth - plugins that use the 'X-Auth-Token' header. However due to the way - plugins evolved this method is required and often called to trigger an - authentication request on a new plugin. - - When implementing a new plugin it is advised that you implement this - method, however if you don't require the 'X-Auth-Token' header override - the `get_headers` method instead. - - :param session: A session object so the plugin can make HTTP calls. - :type session: keystoneclient.session.Session - - :return: A token to use. - :rtype: string - """ - return None - - def get_headers(self, session, **kwargs): - """Fetch authentication headers for message. - - This is a more generalized replacement of the older get_token to allow - plugins to specify different or additional authentication headers to - the OpenStack standard 'X-Auth-Token' header. - - How the authentication headers are obtained is up to the plugin. If the - headers are still valid they may be re-used, retrieved from cache or - the plugin may invoke an authentication request against a server. - - The default implementation of get_headers calls the `get_token` method - to enable older style plugins to continue functioning unchanged. - Subclasses should feel free to completely override this function to - provide the headers that they want. - - There are no required kwargs. They are passed directly to the auth - plugin and they are implementation specific. - - Returning None will indicate that no token was able to be retrieved and - that authorization was a failure. Adding no authentication data can be - achieved by returning an empty dictionary. - - :param session: The session object that the auth_plugin belongs to. - :type session: keystoneclient.session.Session - - :returns: Headers that are set to authenticate a message or None for - failure. Note that when checking this value that the empty - dict is a valid, non-failure response. - :rtype: dict - """ - token = self.get_token(session) - - if not token: - return None - - return {IDENTITY_AUTH_HEADER_NAME: token} - - def get_endpoint(self, session, **kwargs): - """Return an endpoint for the client. - - There are no required keyword arguments to ``get_endpoint`` as a plugin - implementation should use best effort with the information available to - determine the endpoint. However there are certain standard options that - will be generated by the clients and should be used by plugins: - - - ``service_type``: what sort of service is required. - - ``service_name``: the name of the service in the catalog. - - ``interface``: what visibility the endpoint should have. - - ``region_name``: the region the endpoint exists in. - - :param session: The session object that the auth_plugin belongs to. - :type session: keystoneclient.session.Session - - :returns: The base URL that will be used to talk to the required - service or None if not available. - :rtype: string - """ - return None - - def get_connection_params(self, session, **kwargs): - """Return any additional connection parameters required for the plugin. - - :param session: The session object that the auth_plugin belongs to. - :type session: keystoneclient.session.Session - - :returns: Headers that are set to authenticate a message or None for - failure. Note that when checking this value that the empty - dict is a valid, non-failure response. - :rtype: dict - """ - return {} - - def invalidate(self): - """Invalidate the current authentication data. - - This should result in fetching a new token on next call. - - A plugin may be invalidated if an Unauthorized HTTP response is - returned to indicate that the token may have been revoked or is - otherwise now invalid. - - :returns: True if there was something that the plugin did to - invalidate. This means that it makes sense to try again. If - nothing happens returns False to indicate give up. - :rtype: bool - """ - return False - - def get_user_id(self, session, **kwargs): - """Return a unique user identifier of the plugin. - - Wherever possible the user id should be inferred from the token however - there are certain URLs and other places that require access to the - currently authenticated user id. - - :param session: A session object so the plugin can make HTTP calls. - :type session: keystoneclient.session.Session - - :returns: A user identifier or None if one is not available. - :rtype: str - """ - return None - - def get_project_id(self, session, **kwargs): - """Return the project id that we are authenticated to. - - Wherever possible the project id should be inferred from the token - however there are certain URLs and other places that require access to - the currently authenticated project id. - - :param session: A session object so the plugin can make HTTP calls. - :type session: keystoneclient.session.Session - - :returns: A project identifier or None if one is not available. - :rtype: str - """ - return None - - @classmethod - def get_options(cls): - """Return the list of parameters associated with the auth plugin. - - This list may be used to generate CLI or config arguments. - - :returns: A list of Param objects describing available plugin - parameters. - :rtype: List - """ - return [] - - @classmethod - def load_from_options(cls, **kwargs): - """Create a plugin from the arguments retrieved from get_options. - - A client can override this function to do argument validation or to - handle differences between the registered options and what is required - to create the plugin. - """ - return cls(**kwargs) - - @classmethod - def register_argparse_arguments(cls, parser): - """Register the CLI options provided by a specific plugin. - - Given a plugin class convert it's options into argparse arguments and - add them to a parser. - - :param parser: the parser to attach argparse options. - :type parser: argparse.ArgumentParser - """ - # NOTE(jamielennox): ideally oslo_config would be smart enough to - # handle all the Opt manipulation that goes on in this file. However it - # is currently not. Options are handled in as similar a way as - # possible to oslo_config such that when available we should be able to - # transition. - - for opt in cls.get_options(): - args = [] - envs = [] - - for o in [opt] + opt.deprecated_opts: - args.append('--os-%s' % o.name) - envs.append('OS_%s' % o.name.replace('-', '_').upper()) - - # select the first ENV that is not false-y or return None - env_vars = (os.environ.get(e) for e in envs) - default = six.next(six.moves.filter(None, env_vars), None) - - parser.add_argument(*args, - default=default or opt.default, - metavar=opt.metavar, - help=opt.help, - dest='os_%s' % opt.dest) - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - """Load a specific plugin object from an argparse result. - - Convert the results of a parse into the specified plugin. - - :param namespace: The result from CLI parsing. - :type namespace: argparse.Namespace - - :returns: An auth plugin, or None if a name is not provided. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - """ - def _getter(opt): - return getattr(namespace, 'os_%s' % opt.dest) - - return cls.load_from_options_getter(_getter, **kwargs) - - @classmethod - def register_conf_options(cls, conf, group): - """Register the oslo_config options that are needed for a plugin. - - :param conf: A config object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - """ - plugin_opts = cls.get_options() - conf.register_opts(plugin_opts, group=group) - - @classmethod - def load_from_conf_options(cls, conf, group, **kwargs): - """Load the plugin from a CONF object. - - Convert the options already registered into a real plugin. - - :param conf: A config object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - - :returns: An authentication Plugin. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - """ - def _getter(opt): - return conf[group][opt.dest] - - return cls.load_from_options_getter(_getter, **kwargs) - - @classmethod - def load_from_options_getter(cls, getter, **kwargs): - """Load a plugin from a getter function returning appropriate values. - - To handle cases other than the provided CONF and CLI loading you can - specify a custom loader function that will be queried for the option - value. - - The getter is a function that takes one value, an - :py:class:`oslo_config.cfg.Opt` and returns a value to load with. - - :param getter: A function that returns a value for the given opt. - :type getter: callable - - :returns: An authentication Plugin. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - """ - plugin_opts = cls.get_options() - - for opt in plugin_opts: - val = getter(opt) - if val is not None: - val = opt.type(val) - kwargs.setdefault(opt.dest, val) - - return cls.load_from_options(**kwargs) diff --git a/keystoneclient/auth/cli.py b/keystoneclient/auth/cli.py deleted file mode 100644 index 1b8e0543..00000000 --- a/keystoneclient/auth/cli.py +++ /dev/null @@ -1,97 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import os - -from debtcollector import removals -from positional import positional - -from keystoneclient.auth import base - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -@positional() -def register_argparse_arguments(parser, argv, default=None): - """Register CLI options needed to create a plugin. - - The function inspects the provided arguments so that it can also register - the options required for that specific plugin if available. - - :param argparse.ArgumentParser: the parser to attach argparse options to. - :param List argv: the arguments provided to the application. - :param str/class default: a default plugin name or a plugin object to use - if one isn't specified by the CLI. default: None. - - :returns: The plugin class that will be loaded or None if not provided. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - in_parser = argparse.ArgumentParser(add_help=False) - env_plugin = os.environ.get('OS_AUTH_PLUGIN', default) - for p in (in_parser, parser): - p.add_argument('--os-auth-plugin', - metavar='', - default=env_plugin, - help='The auth plugin to load') - - options, _args = in_parser.parse_known_args(argv) - - if not options.os_auth_plugin: - return None - - if isinstance(options.os_auth_plugin, type): - msg = 'Default Authentication options' - plugin = options.os_auth_plugin - else: - msg = 'Options specific to the %s plugin.' % options.os_auth_plugin - plugin = base.get_plugin_class(options.os_auth_plugin) - - group = parser.add_argument_group('Authentication Options', msg) - plugin.register_argparse_arguments(group) - return plugin - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def load_from_argparse_arguments(namespace, **kwargs): - """Retrieve the created plugin from the completed argparse results. - - Loads and creates the auth plugin from the information parsed from the - command line by argparse. - - :param Namespace namespace: The result from CLI parsing. - - :returns: An auth plugin, or None if a name is not provided. - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - if not namespace.os_auth_plugin: - return None - - if isinstance(namespace.os_auth_plugin, type): - plugin = namespace.os_auth_plugin - else: - plugin = base.get_plugin_class(namespace.os_auth_plugin) - - return plugin.load_from_argparse_arguments(namespace, **kwargs) diff --git a/keystoneclient/auth/conf.py b/keystoneclient/auth/conf.py deleted file mode 100644 index ca3cbcf8..00000000 --- a/keystoneclient/auth/conf.py +++ /dev/null @@ -1,132 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from debtcollector import removals -from oslo_config import cfg - -from keystoneclient.auth import base - -_AUTH_PLUGIN_OPT = cfg.StrOpt('auth_plugin', help='Name of the plugin to load') - -_section_help = 'Config Section from which to load plugin specific options' -_AUTH_SECTION_OPT = cfg.StrOpt('auth_section', help=_section_help) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_common_conf_options(): - """Get the oslo_config options common for all auth plugins. - - These may be useful without being registered for config file generation - or to manipulate the options before registering them yourself. - - The options that are set are: - :auth_plugin: The name of the plugin to load. - :auth_section: The config file section to load options from. - - :returns: A list of oslo_config options. - """ - return [_AUTH_PLUGIN_OPT, _AUTH_SECTION_OPT] - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def get_plugin_options(name): - """Get the oslo_config options for a specific plugin. - - This will be the list of config options that is registered and loaded by - the specified plugin. - - :returns: A list of oslo_config options. - """ - return base.get_plugin_class(name).get_options() - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def register_conf_options(conf, group): - """Register the oslo_config options that are needed for a plugin. - - This only registers the basic options shared by all plugins. Options that - are specific to a plugin are loaded just before they are read. - - The defined options are: - - - auth_plugin: the name of the auth plugin that will be used for - authentication. - - auth_section: the group from which further auth plugin options should be - taken. If section is not provided then the auth plugin options will be - taken from the same group as provided in the parameters. - - :param conf: config object to register with. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The ini group to register options in. - """ - conf.register_opt(_AUTH_SECTION_OPT, group=group) - - # NOTE(jamielennox): plugins are allowed to specify a 'section' which is - # the group that auth options should be taken from. If not present they - # come from the same as the base options were registered in. If present - # then the auth_plugin option may be read from that section so add that - # option. - if conf[group].auth_section: - group = conf[group].auth_section - - conf.register_opt(_AUTH_PLUGIN_OPT, group=group) - - -@removals.remove( - message='keystoneclient auth plugins are deprecated. Use keystoneauth.', - version='2.1.0', - removal_version='3.0.0' -) -def load_from_conf_options(conf, group, **kwargs): - """Load a plugin from an oslo_config CONF object. - - Each plugin will register their own required options and so there is no - standard list and the plugin should be consulted. - - The base options should have been registered with register_conf_options - before this function is called. - - :param conf: A conf object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - - :returns: An authentication Plugin or None if a name is not provided - :rtype: :py:class:`keystoneclient.auth.BaseAuthPlugin` - - :raises keystoneclient.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - # NOTE(jamielennox): plugins are allowed to specify a 'section' which is - # the group that auth options should be taken from. If not present they - # come from the same as the base options were registered in. - if conf[group].auth_section: - group = conf[group].auth_section - - name = conf[group].auth_plugin - if not name: - return None - - plugin_class = base.get_plugin_class(name) - plugin_class.register_conf_options(conf, group) - return plugin_class.load_from_conf_options(conf, group, **kwargs) diff --git a/keystoneclient/auth/identity/__init__.py b/keystoneclient/auth/identity/__init__.py deleted file mode 100644 index 8146c1e5..00000000 --- a/keystoneclient/auth/identity/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.auth.identity import base -from keystoneclient.auth.identity import generic -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 - - -BaseIdentityPlugin = base.BaseIdentityPlugin - -V2Password = v2.Password -V2Token = v2.Token - -V3Password = v3.Password -V3Token = v3.Token - -Password = generic.Password -Token = generic.Token - - -__all__ = ('BaseIdentityPlugin', - 'Password', - 'Token', - 'V2Password', - 'V2Token', - 'V3Password', - 'V3Token') diff --git a/keystoneclient/auth/identity/access.py b/keystoneclient/auth/identity/access.py deleted file mode 100644 index 5849b757..00000000 --- a/keystoneclient/auth/identity/access.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient.auth.identity import base - - -class AccessInfoPlugin(base.BaseIdentityPlugin): - """A plugin that turns an existing AccessInfo object into a usable plugin. - - There are cases where reuse of an auth_ref or AccessInfo object is - warranted such as from a cache, from auth_token middleware, or another - source. - - Turn the existing access info object into an identity plugin. This plugin - cannot be refreshed as the AccessInfo object does not contain any - authorizing information. - - :param auth_ref: the existing AccessInfo object. - :type auth_ref: keystoneclient.access.AccessInfo - :param auth_url: the url where this AccessInfo was retrieved from. Required - if using the AUTH_INTERFACE with get_endpoint. (optional) - """ - - @positional() - def __init__(self, auth_ref, auth_url=None): - super(AccessInfoPlugin, self).__init__(auth_url=auth_url, - reauthenticate=False) - self.auth_ref = auth_ref - - def get_auth_ref(self, session, **kwargs): - return self.auth_ref - - def invalidate(self): - # NOTE(jamielennox): Don't allow the default invalidation to occur - # because on next authentication request we will only get the same - # auth_ref object again. - return False diff --git a/keystoneclient/auth/identity/base.py b/keystoneclient/auth/identity/base.py deleted file mode 100644 index b20d3e27..00000000 --- a/keystoneclient/auth/identity/base.py +++ /dev/null @@ -1,422 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import logging -import threading -import warnings - -from oslo_config import cfg -from positional import positional -import six - -from keystoneclient import _discover -from keystoneclient.auth import base -from keystoneclient import exceptions - -LOG = logging.getLogger(__name__) - - -def get_options(): - return [ - cfg.StrOpt('auth-url', help='Authentication URL'), - ] - - -@six.add_metaclass(abc.ABCMeta) -class BaseIdentityPlugin(base.BaseAuthPlugin): - - # we count a token as valid (not needing refreshing) if it is valid for at - # least this many seconds before the token expiry time - MIN_TOKEN_LIFE_SECONDS = 120 - - def __init__(self, - auth_url=None, - username=None, - password=None, - token=None, - trust_id=None, - reauthenticate=True): - - super(BaseIdentityPlugin, self).__init__() - - warnings.warn( - 'keystoneclient auth plugins are deprecated as of the 2.1.0 ' - 'release in favor of keystoneauth1 plugins. They will be removed ' - 'in future releases.', DeprecationWarning) - - self.auth_url = auth_url - self.auth_ref = None - self.reauthenticate = reauthenticate - - self._endpoint_cache = {} - self._lock = threading.Lock() - - self._username = username - self._password = password - self._token = token - self._trust_id = trust_id - - @property - def username(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'username is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._username - - @username.setter - def username(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'username is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._username = value - - @property - def password(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'password is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._password - - @password.setter - def password(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'password is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._password = value - - @property - def token(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'token is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._token - - @token.setter - def token(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'token is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._token = value - - @property - def trust_id(self): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'trust_id is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - """Deprecated as of the 1.7.0 release. - - It may be removed in the 2.0.0 release. - """ - warnings.warn( - 'trust_id is deprecated as of the 1.7.0 release and may be ' - 'removed in the 2.0.0 release.', DeprecationWarning) - - self._trust_id = value - - @abc.abstractmethod - def get_auth_ref(self, session, **kwargs): - """Obtain a token from an OpenStack Identity Service. - - This method is overridden by the various token version plugins. - - This method should not be called independently and is expected to be - invoked via the do_authenticate() method. - - This method will be invoked if the AccessInfo object cached by the - plugin is not valid. Thus plugins should always fetch a new AccessInfo - when invoked. If you are looking to just retrieve the current auth data - then you should use get_access(). - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.InvalidResponse: The response - returned wasn't - appropriate. - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :returns: Token access information. - :rtype: :py:class:`keystoneclient.access.AccessInfo` - """ - pass # pragma: no cover - - def get_token(self, session, **kwargs): - """Return a valid auth token. - - If a valid token is not present then a new one will be fetched. - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :return: A valid token. - :rtype: string - """ - return self.get_access(session).auth_token - - def _needs_reauthenticate(self): - """Return if the existing token needs to be re-authenticated. - - The token should be refreshed if it is about to expire. - - :returns: True if the plugin should fetch a new token. False otherwise. - """ - if not self.auth_ref: - # authentication was never fetched. - return True - - if not self.reauthenticate: - # don't re-authenticate if it has been disallowed. - return False - - if self.auth_ref.will_expire_soon(self.MIN_TOKEN_LIFE_SECONDS): - # if it's about to expire we should re-authenticate now. - return True - - # otherwise it's fine and use the existing one. - return False - - def get_access(self, session, **kwargs): - """Fetch or return a current AccessInfo object. - - If a valid AccessInfo is present then it is returned otherwise a new - one will be fetched. - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :returns: Valid AccessInfo - :rtype: :py:class:`keystoneclient.access.AccessInfo` - """ - # Hey Kids! Thread safety is important particularly in the case where - # a service is creating an admin style plugin that will then proceed - # to make calls from many threads. As a token expires all the threads - # will try and fetch a new token at once, so we want to ensure that - # only one thread tries to actually fetch from keystone at once. - with self._lock: - if self._needs_reauthenticate(): - self.auth_ref = self.get_auth_ref(session) - - return self.auth_ref - - def invalidate(self): - """Invalidate the current authentication data. - - This should result in fetching a new token on next call. - - A plugin may be invalidated if an Unauthorized HTTP response is - returned to indicate that the token may have been revoked or is - otherwise now invalid. - - :returns: True if there was something that the plugin did to - invalidate. This means that it makes sense to try again. If - nothing happens returns False to indicate give up. - :rtype: bool - """ - if self.auth_ref: - self.auth_ref = None - return True - - return False - - def get_endpoint(self, session, service_type=None, interface=None, - region_name=None, service_name=None, version=None, - **kwargs): - """Return a valid endpoint for a service. - - If a valid token is not present then a new one will be fetched using - the session and kwargs. - - :param session: A session object that can be used for communication. - :type session: keystoneclient.session.Session - :param string service_type: The type of service to lookup the endpoint - for. This plugin will return None (failure) - if service_type is not provided. - :param string interface: The exposure of the endpoint. Should be - `public`, `internal`, `admin`, or `auth`. - `auth` is special here to use the `auth_url` - rather than a URL extracted from the service - catalog. Defaults to `public`. - :param string region_name: The region the endpoint should exist in. - (optional) - :param string service_name: The name of the service in the catalog. - (optional) - :param tuple version: The minimum version number required for this - endpoint. (optional) - - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :return: A valid endpoint URL or None if not available. - :rtype: string or None - """ - # NOTE(jamielennox): if you specifically ask for requests to be sent to - # the auth url then we can ignore many of the checks. Typically if you - # are asking for the auth endpoint it means that there is no catalog to - # query however we still need to support asking for a specific version - # of the auth_url for generic plugins. - if interface is base.AUTH_INTERFACE: - url = self.auth_url - service_type = service_type or 'identity' - - else: - if not service_type: - LOG.warning( - 'Plugin cannot return an endpoint without knowing the ' - 'service type that is required. Add service_type to ' - 'endpoint filtering data.') - return None - - if not interface: - interface = 'public' - - service_catalog = self.get_access(session).service_catalog - url = service_catalog.url_for(service_type=service_type, - endpoint_type=interface, - region_name=region_name, - service_name=service_name) - - if not version: - # NOTE(jamielennox): This may not be the best thing to default to - # but is here for backwards compatibility. It may be worth - # defaulting to the most recent version. - return url - - # NOTE(jamielennox): For backwards compatibility people might have a - # versioned endpoint in their catalog even though they want to use - # other endpoint versions. So we support a list of client defined - # situations where we can strip the version component from a URL before - # doing discovery. - hacked_url = _discover.get_catalog_discover_hack(service_type, url) - - try: - disc = self.get_discovery(session, hacked_url, authenticated=False) - except (exceptions.DiscoveryFailure, - exceptions.HTTPError, - exceptions.ConnectionError): - # NOTE(jamielennox): Again if we can't contact the server we fall - # back to just returning the URL from the catalog. This may not be - # the best default but we need it for now. - LOG.warning( - 'Failed to contact the endpoint at %s for discovery. Fallback ' - 'to using that endpoint as the base url.', url) - else: - url = disc.url_for(version) - - return url - - def get_user_id(self, session, **kwargs): - return self.get_access(session).user_id - - def get_project_id(self, session, **kwargs): - return self.get_access(session).project_id - - @positional() - def get_discovery(self, session, url, authenticated=None): - """Return the discovery object for a URL. - - Check the session and the plugin cache to see if we have already - performed discovery on the URL and if so return it, otherwise create - a new discovery object, cache it and return it. - - This function is expected to be used by subclasses and should not - be needed by users. - - :param session: A session object to discover with. - :type session: keystoneclient.session.Session - :param str url: The url to lookup. - :param bool authenticated: Include a token in the discovery call. - (optional) Defaults to None (use a token - if a plugin is installed). - - :raises keystoneclient.exceptions.DiscoveryFailure: if for some reason - the lookup fails. - :raises keystoneclient.exceptions.HttpError: An error from an invalid - HTTP response. - - :returns: A discovery object with the results of looking up that URL. - """ - # NOTE(jamielennox): we want to cache endpoints on the session as well - # so that they maintain sharing between auth plugins. Create a cache on - # the session if it doesn't exist already. - try: - session_endpoint_cache = session._identity_endpoint_cache - except AttributeError: - session_endpoint_cache = session._identity_endpoint_cache = {} - - # NOTE(jamielennox): There is a cache located on both the session - # object and the auth plugin object so that they can be shared and the - # cache is still usable - for cache in (self._endpoint_cache, session_endpoint_cache): - disc = cache.get(url) - - if disc: - break - else: - disc = _discover.Discover(session, url, - authenticated=authenticated) - self._endpoint_cache[url] = disc - session_endpoint_cache[url] = disc - - return disc - - @classmethod - def get_options(cls): - options = super(BaseIdentityPlugin, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneclient/auth/identity/generic/__init__.py b/keystoneclient/auth/identity/generic/__init__.py deleted file mode 100644 index a96fb979..00000000 --- a/keystoneclient/auth/identity/generic/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.auth.identity.generic.base import BaseGenericPlugin # noqa -from keystoneclient.auth.identity.generic.password import Password # noqa -from keystoneclient.auth.identity.generic.token import Token # noqa - - -__all__ = ('BaseGenericPlugin', - 'Password', - 'Token', - ) diff --git a/keystoneclient/auth/identity/generic/base.py b/keystoneclient/auth/identity/generic/base.py deleted file mode 100644 index 98680ef9..00000000 --- a/keystoneclient/auth/identity/generic/base.py +++ /dev/null @@ -1,192 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import logging - -from oslo_config import cfg -import six -import six.moves.urllib.parse as urlparse - -from keystoneclient import _discover -from keystoneclient.auth.identity import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -LOG = logging.getLogger(__name__) - - -def get_options(): - return [ - cfg.StrOpt('domain-id', help='Domain ID to scope to'), - cfg.StrOpt('domain-name', help='Domain name to scope to'), - cfg.StrOpt('tenant-id', help='Tenant ID to scope to'), - cfg.StrOpt('tenant-name', help='Tenant name to scope to'), - cfg.StrOpt('project-id', help='Project ID to scope to'), - cfg.StrOpt('project-name', help='Project name to scope to'), - cfg.StrOpt('project-domain-id', - help='Domain ID containing project'), - cfg.StrOpt('project-domain-name', - help='Domain name containing project'), - cfg.StrOpt('trust-id', help='Trust ID'), - ] - - -@six.add_metaclass(abc.ABCMeta) -class BaseGenericPlugin(base.BaseIdentityPlugin): - """An identity plugin that is not version dependent. - - Internally we will construct a version dependent plugin with the resolved - URL and then proxy all calls from the base plugin to the versioned one. - """ - - def __init__(self, auth_url, - tenant_id=None, - tenant_name=None, - project_id=None, - project_name=None, - project_domain_id=None, - project_domain_name=None, - domain_id=None, - domain_name=None, - trust_id=None): - super(BaseGenericPlugin, self).__init__(auth_url=auth_url) - - self._project_id = project_id or tenant_id - self._project_name = project_name or tenant_name - self._project_domain_id = project_domain_id - self._project_domain_name = project_domain_name - self._domain_id = domain_id - self._domain_name = domain_name - self._trust_id = trust_id - - self._plugin = None - - @property - def trust_id(self): - # Override to remove deprecation. - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - # Override to remove deprecation. - self._trust_id = value - - @abc.abstractmethod - def create_plugin(self, session, version, url, raw_status=None): - """Create a plugin from the given parameters. - - This function will be called multiple times with the version and url - of a potential endpoint. If a plugin can be constructed that fits the - params then it should return it. If not return None and then another - call will be made with other available URLs. - - :param session: A session object. - :type session: keystoneclient.session.Session - :param tuple version: A tuple of the API version at the URL. - :param string url: The base URL for this version. - :param string raw_status: The status that was in the discovery field. - - :returns: A plugin that can match the parameters or None if nothing. - """ - return None # pragma: no cover - - @property - def _has_domain_scope(self): - """Are there domain parameters. - - Domain parameters are v3 only so returns if any are set. - - :returns: True if a domain parameter is set, false otherwise. - """ - return any([self._domain_id, self._domain_name, - self._project_domain_id, self._project_domain_name]) - - @property - def _v2_params(self): - """Return parameters that are common to v2 plugins.""" - return {'trust_id': self._trust_id, - 'tenant_id': self._project_id, - 'tenant_name': self._project_name} - - @property - def _v3_params(self): - """Return parameters that are common to v3 plugins.""" - return {'trust_id': self._trust_id, - 'project_id': self._project_id, - 'project_name': self._project_name, - 'project_domain_id': self._project_domain_id, - 'project_domain_name': self._project_domain_name, - 'domain_id': self._domain_id, - 'domain_name': self._domain_name} - - def _do_create_plugin(self, session): - plugin = None - - try: - disc = self.get_discovery(session, - self.auth_url, - authenticated=False) - except (exceptions.DiscoveryFailure, - exceptions.HTTPError, - exceptions.ConnectionError): - LOG.warning('Discovering versions from the identity service ' - 'failed when creating the password plugin. ' - 'Attempting to determine version from URL.') - - url_parts = urlparse.urlparse(self.auth_url) - path = url_parts.path.lower() - - if path.startswith('/v2.0') and not self._has_domain_scope: - plugin = self.create_plugin(session, (2, 0), self.auth_url) - elif path.startswith('/v3'): - plugin = self.create_plugin(session, (3, 0), self.auth_url) - - else: - disc_data = disc.version_data() - - for data in disc_data: - version = data['version'] - - if (_discover.version_match((2,), version) and - self._has_domain_scope): - # NOTE(jamielennox): if there are domain parameters there - # is no point even trying against v2 APIs. - continue - - plugin = self.create_plugin(session, - version, - data['url'], - raw_status=data['raw_status']) - - if plugin: - break - - if plugin: - return plugin - - # so there were no URLs that i could use for auth of any version. - msg = _('Could not determine a suitable URL for the plugin') - raise exceptions.DiscoveryFailure(msg) - - def get_auth_ref(self, session, **kwargs): - if not self._plugin: - self._plugin = self._do_create_plugin(session) - - return self._plugin.get_auth_ref(session, **kwargs) - - @classmethod - def get_options(cls): - options = super(BaseGenericPlugin, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneclient/auth/identity/generic/cli.py b/keystoneclient/auth/identity/generic/cli.py deleted file mode 100644 index 9debf631..00000000 --- a/keystoneclient/auth/identity/generic/cli.py +++ /dev/null @@ -1,84 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg -from positional import positional - -from keystoneclient.auth.identity.generic import password -from keystoneclient import exceptions as exc -from keystoneclient.i18n import _ - - -class DefaultCLI(password.Password): - """A Plugin that provides typical authentication options for CLIs. - - This plugin provides standard username and password authentication options - as well as allowing users to override with a custom token and endpoint. - """ - - @positional() - def __init__(self, endpoint=None, token=None, **kwargs): - super(DefaultCLI, self).__init__(**kwargs) - - self._token = token - self._endpoint = endpoint - - @classmethod - def get_options(cls): - options = super(DefaultCLI, cls).get_options() - options.extend([cfg.StrOpt('endpoint', - help='A URL to use instead of a catalog'), - cfg.StrOpt('token', - secret=True, - help='Always use the specified token')]) - return options - - def get_token(self, *args, **kwargs): - if self._token: - return self._token - - return super(DefaultCLI, self).get_token(*args, **kwargs) - - def get_endpoint(self, *args, **kwargs): - if self._endpoint: - return self._endpoint - - return super(DefaultCLI, self).get_endpoint(*args, **kwargs) - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - token = kwargs.get('token') or namespace.os_token - endpoint = kwargs.get('endpoint') or namespace.os_endpoint - auth_url = kwargs.get('auth_url') or namespace.os_auth_url - - if token and not endpoint: - # if a user provides a token then they must also provide an - # endpoint because we aren't fetching a token to get a catalog from - msg = _('A service URL must be provided with a token') - raise exc.CommandError(msg) - elif (not token) and (not auth_url): - # if you don't provide a token you are going to provide at least an - # auth_url with which to authenticate. - raise exc.CommandError(_('Expecting an auth URL via either ' - '--os-auth-url or env[OS_AUTH_URL]')) - - plugin = super(DefaultCLI, cls).load_from_argparse_arguments(namespace, - **kwargs) - - if (not token) and (not plugin._password): - # we do this after the load so that the base plugin has an - # opportunity to prompt the user for a password - raise exc.CommandError(_('Expecting a password provided via ' - 'either --os-password, env[OS_PASSWORD], ' - 'or prompted response')) - - return plugin diff --git a/keystoneclient/auth/identity/generic/password.py b/keystoneclient/auth/identity/generic/password.py deleted file mode 100644 index 873e2539..00000000 --- a/keystoneclient/auth/identity/generic/password.py +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg -from positional import positional - -from keystoneclient import _discover -from keystoneclient.auth.identity.generic import base -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 -from keystoneclient import utils - - -def get_options(): - return [ - cfg.StrOpt('user-id', help='User id'), - cfg.StrOpt('username', dest='username', help='Username', - deprecated_name='user-name'), - cfg.StrOpt('user-domain-id', help="User's domain id"), - cfg.StrOpt('user-domain-name', help="User's domain name"), - cfg.StrOpt('password', secret=True, help="User's password"), - ] - - -class Password(base.BaseGenericPlugin): - """A common user/password authentication plugin. - - :param string username: Username for authentication. - :param string user_id: User ID for authentication. - :param string password: Password for authentication. - :param string user_domain_id: User's domain ID for authentication. - :param string user_domain_name: User's domain name for authentication. - - """ - - @positional() - def __init__(self, auth_url, username=None, user_id=None, password=None, - user_domain_id=None, user_domain_name=None, **kwargs): - super(Password, self).__init__(auth_url=auth_url, **kwargs) - - self._username = username - self._user_id = user_id - self._password = password - self._user_domain_id = user_domain_id - self._user_domain_name = user_domain_name - - def create_plugin(self, session, version, url, raw_status=None): - if _discover.version_match((2,), version): - if self._user_domain_id or self._user_domain_name: - # If you specify any domain parameters it won't work so quit. - return None - - return v2.Password(auth_url=url, - user_id=self._user_id, - username=self._username, - password=self._password, - **self._v2_params) - - elif _discover.version_match((3,), version): - return v3.Password(auth_url=url, - user_id=self._user_id, - username=self._username, - user_domain_id=self._user_domain_id, - user_domain_name=self._user_domain_name, - password=self._password, - **self._v3_params) - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - options.extend(get_options()) - return options - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - if not (kwargs.get('password') or namespace.os_password): - kwargs['password'] = utils.prompt_user_password() - - return super(Password, cls).load_from_argparse_arguments(namespace, - **kwargs) diff --git a/keystoneclient/auth/identity/generic/token.py b/keystoneclient/auth/identity/generic/token.py deleted file mode 100644 index e3d01aa0..00000000 --- a/keystoneclient/auth/identity/generic/token.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg - -from keystoneclient import _discover -from keystoneclient.auth.identity.generic import base -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 - - -def get_options(): - return [ - cfg.StrOpt('token', secret=True, help='Token to authenticate with'), - ] - - -class Token(base.BaseGenericPlugin): - """Generic token auth plugin. - - :param string token: Token for authentication. - """ - - def __init__(self, auth_url, token=None, **kwargs): - super(Token, self).__init__(auth_url, **kwargs) - self._token = token - - def create_plugin(self, session, version, url, raw_status=None): - if _discover.version_match((2,), version): - return v2.Token(url, self._token, **self._v2_params) - - elif _discover.version_match((3,), version): - return v3.Token(url, self._token, **self._v3_params) - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneclient/auth/identity/v2.py b/keystoneclient/auth/identity/v2.py deleted file mode 100644 index 6a403dcd..00000000 --- a/keystoneclient/auth/identity/v2.py +++ /dev/null @@ -1,242 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import logging - -from oslo_config import cfg -from positional import positional -import six - -from keystoneclient import access -from keystoneclient.auth.identity import base -from keystoneclient import exceptions -from keystoneclient import utils - -_logger = logging.getLogger(__name__) - - -@six.add_metaclass(abc.ABCMeta) -class Auth(base.BaseIdentityPlugin): - """Identity V2 Authentication Plugin. - - :param string auth_url: Identity service endpoint for authorization. - :param string trust_id: Trust ID for trust scoping. - :param string tenant_id: Tenant ID for project scoping. - :param string tenant_name: Tenant name for project scoping. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - @classmethod - def get_options(cls): - options = super(Auth, cls).get_options() - - options.extend([ - cfg.StrOpt('tenant-id', help='Tenant ID'), - cfg.StrOpt('tenant-name', help='Tenant Name'), - cfg.StrOpt('trust-id', help='Trust ID'), - ]) - - return options - - @positional() - def __init__(self, auth_url, - trust_id=None, - tenant_id=None, - tenant_name=None, - reauthenticate=True): - super(Auth, self).__init__(auth_url=auth_url, - reauthenticate=reauthenticate) - - self._trust_id = trust_id - self.tenant_id = tenant_id - self.tenant_name = tenant_name - - @property - def trust_id(self): - # Override to remove deprecation. - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - # Override to remove deprecation. - self._trust_id = value - - def get_auth_ref(self, session, **kwargs): - headers = {'Accept': 'application/json'} - url = self.auth_url.rstrip('/') + '/tokens' - params = {'auth': self.get_auth_data(headers)} - - if self.tenant_id: - params['auth']['tenantId'] = self.tenant_id - elif self.tenant_name: - params['auth']['tenantName'] = self.tenant_name - if self.trust_id: - params['auth']['trust_id'] = self.trust_id - - _logger.debug('Making authentication request to %s', url) - resp = session.post(url, json=params, headers=headers, - authenticated=False, log=False) - - try: - resp_data = resp.json()['access'] - except (KeyError, ValueError): - raise exceptions.InvalidResponse(response=resp) - - return access.AccessInfoV2(**resp_data) - - @abc.abstractmethod - def get_auth_data(self, headers=None): - """Return the authentication section of an auth plugin. - - :param dict headers: The headers that will be sent with the auth - request if a plugin needs to add to them. - :return: A dict of authentication data for the auth type. - :rtype: dict - """ - pass # pragma: no cover - - -_NOT_PASSED = object() - - -class Password(Auth): - """A plugin for authenticating with a username and password. - - A username or user_id must be provided. - - :param string auth_url: Identity service endpoint for authorization. - :param string username: Username for authentication. - :param string password: Password for authentication. - :param string user_id: User ID for authentication. - :param string trust_id: Trust ID for trust scoping. - :param string tenant_id: Tenant ID for tenant scoping. - :param string tenant_name: Tenant name for tenant scoping. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - - :raises TypeError: if a user_id or username is not provided. - """ - - @positional(4) - def __init__(self, auth_url, username=_NOT_PASSED, password=None, - user_id=_NOT_PASSED, **kwargs): - super(Password, self).__init__(auth_url, **kwargs) - - if username is _NOT_PASSED and user_id is _NOT_PASSED: - msg = 'You need to specify either a username or user_id' - raise TypeError(msg) - - if username is _NOT_PASSED: - username = None - if user_id is _NOT_PASSED: - user_id = None - - self.user_id = user_id - self._username = username - self._password = password - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - def get_auth_data(self, headers=None): - auth = {'password': self.password} - - if self.username: - auth['username'] = self.username - elif self.user_id: - auth['userId'] = self.user_id - - return {'passwordCredentials': auth} - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - if not (kwargs.get('password') or namespace.os_password): - kwargs['password'] = utils.prompt_user_password() - - return super(Password, cls).load_from_argparse_arguments(namespace, - **kwargs) - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - - options.extend([ - cfg.StrOpt('username', - dest='username', - deprecated_name='user-name', - help='Username to login with'), - cfg.StrOpt('user-id', help='User ID to login with'), - cfg.StrOpt('password', secret=True, help='Password to use'), - ]) - - return options - - -class Token(Auth): - """A plugin for authenticating with an existing token. - - :param string auth_url: Identity service endpoint for authorization. - :param string token: Existing token for authentication. - :param string tenant_id: Tenant ID for tenant scoping. - :param string tenant_name: Tenant name for tenant scoping. - :param string trust_id: Trust ID for trust scoping. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - def __init__(self, auth_url, token, **kwargs): - super(Token, self).__init__(auth_url, **kwargs) - self._token = token - - @property - def token(self): - # Override to remove deprecation. - return self._token - - @token.setter - def token(self, value): - # Override to remove deprecation. - self._token = value - - def get_auth_data(self, headers=None): - if headers is not None: - headers['X-Auth-Token'] = self.token - return {'token': {'id': self.token}} - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('token', secret=True, help='Token'), - ]) - - return options diff --git a/keystoneclient/auth/identity/v3/__init__.py b/keystoneclient/auth/identity/v3/__init__.py deleted file mode 100644 index f25bf5e2..00000000 --- a/keystoneclient/auth/identity/v3/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.auth.identity.v3.base import * # noqa -from keystoneclient.auth.identity.v3.federated import * # noqa -from keystoneclient.auth.identity.v3.password import * # noqa -from keystoneclient.auth.identity.v3.token import * # noqa - - -__all__ = ('Auth', - 'AuthConstructor', - 'AuthMethod', - 'BaseAuth', - - 'FederatedBaseAuth', - - 'Password', - 'PasswordMethod', - - 'Token', - 'TokenMethod') diff --git a/keystoneclient/auth/identity/v3/base.py b/keystoneclient/auth/identity/v3/base.py deleted file mode 100644 index 3576045a..00000000 --- a/keystoneclient/auth/identity/v3/base.py +++ /dev/null @@ -1,265 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import json -import logging - -from oslo_config import cfg -from positional import positional -import six - -from keystoneclient import access -from keystoneclient.auth.identity import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - -_logger = logging.getLogger(__name__) - -__all__ = ('Auth', 'AuthMethod', 'AuthConstructor', 'BaseAuth') - - -@six.add_metaclass(abc.ABCMeta) -class BaseAuth(base.BaseIdentityPlugin): - """Identity V3 Authentication Plugin. - - :param string auth_url: Identity service endpoint for authentication. - :param List auth_methods: A collection of methods to authenticate with. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - :param bool include_catalog: Include the service catalog in the returned - token. (optional) default True. - """ - - @positional() - def __init__(self, auth_url, - trust_id=None, - domain_id=None, - domain_name=None, - project_id=None, - project_name=None, - project_domain_id=None, - project_domain_name=None, - reauthenticate=True, - include_catalog=True): - super(BaseAuth, self).__init__(auth_url=auth_url, - reauthenticate=reauthenticate) - self._trust_id = trust_id - self.domain_id = domain_id - self.domain_name = domain_name - self.project_id = project_id - self.project_name = project_name - self.project_domain_id = project_domain_id - self.project_domain_name = project_domain_name - self.include_catalog = include_catalog - - @property - def trust_id(self): - # Override to remove deprecation. - return self._trust_id - - @trust_id.setter - def trust_id(self, value): - # Override to remove deprecation. - self._trust_id = value - - @property - def token_url(self): - """The full URL where we will send authentication data.""" - return '%s/auth/tokens' % self.auth_url.rstrip('/') - - @abc.abstractmethod - def get_auth_ref(self, session, **kwargs): - return None # pragma: no cover - - @classmethod - def get_options(cls): - options = super(BaseAuth, cls).get_options() - - options.extend([ - cfg.StrOpt('domain-id', help='Domain ID to scope to'), - cfg.StrOpt('domain-name', help='Domain name to scope to'), - cfg.StrOpt('project-id', help='Project ID to scope to'), - cfg.StrOpt('project-name', help='Project name to scope to'), - cfg.StrOpt('project-domain-id', - help='Domain ID containing project'), - cfg.StrOpt('project-domain-name', - help='Domain name containing project'), - cfg.StrOpt('trust-id', help='Trust ID'), - ]) - - return options - - -class Auth(BaseAuth): - """Identity V3 Authentication Plugin. - - :param string auth_url: Identity service endpoint for authentication. - :param List auth_methods: A collection of methods to authenticate with. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - :param bool include_catalog: Include the service catalog in the returned - token. (optional) default True. - :param bool unscoped: Force the return of an unscoped token. This will make - the keystone server return an unscoped token even if - a default_project_id is set for this user. - """ - - def __init__(self, auth_url, auth_methods, **kwargs): - self.unscoped = kwargs.pop('unscoped', False) - super(Auth, self).__init__(auth_url=auth_url, **kwargs) - self.auth_methods = auth_methods - - def get_auth_ref(self, session, **kwargs): - headers = {'Accept': 'application/json'} - body = {'auth': {'identity': {}}} - ident = body['auth']['identity'] - rkwargs = {} - - for method in self.auth_methods: - name, auth_data = method.get_auth_data(session, - self, - headers, - request_kwargs=rkwargs) - ident.setdefault('methods', []).append(name) - ident[name] = auth_data - - if not ident: - raise exceptions.AuthorizationFailure( - _('Authentication method required (e.g. password)')) - - mutual_exclusion = [bool(self.domain_id or self.domain_name), - bool(self.project_id or self.project_name), - bool(self.trust_id), - bool(self.unscoped)] - - if sum(mutual_exclusion) > 1: - raise exceptions.AuthorizationFailure( - _('Authentication cannot be scoped to multiple targets. Pick ' - 'one of: project, domain, trust or unscoped')) - - if self.domain_id: - body['auth']['scope'] = {'domain': {'id': self.domain_id}} - elif self.domain_name: - body['auth']['scope'] = {'domain': {'name': self.domain_name}} - elif self.project_id: - body['auth']['scope'] = {'project': {'id': self.project_id}} - elif self.project_name: - scope = body['auth']['scope'] = {'project': {}} - scope['project']['name'] = self.project_name - - if self.project_domain_id: - scope['project']['domain'] = {'id': self.project_domain_id} - elif self.project_domain_name: - scope['project']['domain'] = {'name': self.project_domain_name} - elif self.trust_id: - body['auth']['scope'] = {'OS-TRUST:trust': {'id': self.trust_id}} - elif self.unscoped: - body['auth']['scope'] = {'unscoped': {}} - - # NOTE(jamielennox): we add nocatalog here rather than in token_url - # directly as some federation plugins require the base token_url - token_url = self.token_url - if not self.include_catalog: - token_url += '?nocatalog' - - _logger.debug('Making authentication request to %s', token_url) - resp = session.post(token_url, json=body, headers=headers, - authenticated=False, log=False, **rkwargs) - - try: - _logger.debug(json.dumps(resp.json())) - resp_data = resp.json()['token'] - except (KeyError, ValueError): - raise exceptions.InvalidResponse(response=resp) - - return access.AccessInfoV3(resp.headers['X-Subject-Token'], - **resp_data) - - -@six.add_metaclass(abc.ABCMeta) -class AuthMethod(object): - """One part of a V3 Authentication strategy. - - V3 Tokens allow multiple methods to be presented when authentication - against the server. Each one of these methods is implemented by an - AuthMethod. - - Note: When implementing an AuthMethod use the method_parameters - and do not use positional arguments. Otherwise they can't be picked up by - the factory method and don't work as well with AuthConstructors. - """ - - _method_parameters = [] - - def __init__(self, **kwargs): - for param in self._method_parameters: - setattr(self, param, kwargs.pop(param, None)) - - if kwargs: - msg = _("Unexpected Attributes: %s") % ", ".join(kwargs) - raise AttributeError(msg) - - @classmethod - def _extract_kwargs(cls, kwargs): - """Remove parameters related to this method from other kwargs.""" - return dict([(p, kwargs.pop(p, None)) - for p in cls._method_parameters]) - - @abc.abstractmethod - def get_auth_data(self, session, auth, headers, **kwargs): - """Return the authentication section of an auth plugin. - - :param session: The communication session. - :type session: keystoneclient.session.Session - :param base.Auth auth: The auth plugin calling the method. - :param dict headers: The headers that will be sent with the auth - request if a plugin needs to add to them. - :return: The identifier of this plugin and a dict of authentication - data for the auth type. - :rtype: tuple(string, dict) - """ - pass # pragma: no cover - - -@six.add_metaclass(abc.ABCMeta) -class AuthConstructor(Auth): - """Abstract base class for creating an Auth Plugin. - - The Auth Plugin created contains only one authentication method. This - is generally the required usage. - - An AuthConstructor creates an AuthMethod based on the method's - arguments and the auth_method_class defined by the plugin. It then - creates the auth plugin with only that authentication method. - """ - - _auth_method_class = None - - def __init__(self, auth_url, *args, **kwargs): - method_kwargs = self._auth_method_class._extract_kwargs(kwargs) - method = self._auth_method_class(*args, **method_kwargs) - super(AuthConstructor, self).__init__(auth_url, [method], **kwargs) diff --git a/keystoneclient/auth/identity/v3/federated.py b/keystoneclient/auth/identity/v3/federated.py deleted file mode 100644 index 97d83e8f..00000000 --- a/keystoneclient/auth/identity/v3/federated.py +++ /dev/null @@ -1,121 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from oslo_config import cfg -import six - -from keystoneclient.auth.identity.v3 import base -from keystoneclient.auth.identity.v3 import token - -__all__ = ('FederatedBaseAuth',) - - -@six.add_metaclass(abc.ABCMeta) -class FederatedBaseAuth(base.BaseAuth): - - rescoping_plugin = token.Token - - def __init__(self, auth_url, identity_provider, protocol, **kwargs): - """Class constructor for federated authentication plugins. - - Accepting following parameters: - - :param auth_url: URL of the Identity Service - :type auth_url: string - :param identity_provider: Name of the Identity Provider the client - will authenticate against. This parameter - will be used to build a dynamic URL used to - obtain unscoped OpenStack token. - :type identity_provider: string - :param protocol: Protocol name configured on the keystone service - provider side - :type protocol: string - - """ - super(FederatedBaseAuth, self).__init__(auth_url=auth_url, **kwargs) - self.identity_provider = identity_provider - self.protocol = protocol - - @classmethod - def get_options(cls): - options = super(FederatedBaseAuth, cls).get_options() - - options.extend([ - cfg.StrOpt('identity-provider', - help="Identity Provider's name"), - cfg.StrOpt('protocol', help="Name of the federated protocol used " - "for federated authentication. Must " - "match its counterpart name " - "configured at the keystone service " - "provider. Typically values would be " - "'saml2' or 'oidc'.") - ]) - - return options - - @property - def federated_token_url(self): - """Full URL where authorization data is sent.""" - values = { - 'host': self.auth_url.rstrip('/'), - 'identity_provider': self.identity_provider, - 'protocol': self.protocol - } - url = ("%(host)s/OS-FEDERATION/identity_providers/" - "%(identity_provider)s/protocols/%(protocol)s/auth") - url = url % values - - return url - - def _get_scoping_data(self): - return {'trust_id': self.trust_id, - 'domain_id': self.domain_id, - 'domain_name': self.domain_name, - 'project_id': self.project_id, - 'project_name': self.project_name, - 'project_domain_id': self.project_domain_id, - 'project_domain_name': self.project_domain_name} - - def get_auth_ref(self, session, **kwargs): - """Authenticate retrieve token information. - - This is a multi-step process where a client does federated authn - receives an unscoped token. - - If an unscoped token is successfully received and scoping information - is present then the token is rescoped to that target. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: a token data representation - :rtype: :py:class:`keystoneclient.access.AccessInfo` - - """ - auth_ref = self.get_unscoped_auth_ref(session) - scoping = self._get_scoping_data() - - if any(scoping.values()): - token_plugin = self.rescoping_plugin(self.auth_url, - token=auth_ref.auth_token, - **scoping) - - auth_ref = token_plugin.get_auth_ref(session) - - return auth_ref - - @abc.abstractmethod - def get_unscoped_auth_ref(self, session, **kwargs): - """Fetch unscoped federated token.""" - pass # pragma: no cover diff --git a/keystoneclient/auth/identity/v3/password.py b/keystoneclient/auth/identity/v3/password.py deleted file mode 100644 index 99094a1e..00000000 --- a/keystoneclient/auth/identity/v3/password.py +++ /dev/null @@ -1,97 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg - -from keystoneclient.auth.identity.v3 import base -from keystoneclient import utils - - -__all__ = ('PasswordMethod', 'Password') - - -class PasswordMethod(base.AuthMethod): - """Construct a User/Password based authentication method. - - :param string password: Password for authentication. - :param string username: Username for authentication. - :param string user_id: User ID for authentication. - :param string user_domain_id: User's domain ID for authentication. - :param string user_domain_name: User's domain name for authentication. - """ - - _method_parameters = ['user_id', - 'username', - 'user_domain_id', - 'user_domain_name', - 'password'] - - def get_auth_data(self, session, auth, headers, **kwargs): - user = {'password': self.password} - - if self.user_id: - user['id'] = self.user_id - elif self.username: - user['name'] = self.username - - if self.user_domain_id: - user['domain'] = {'id': self.user_domain_id} - elif self.user_domain_name: - user['domain'] = {'name': self.user_domain_name} - - return 'password', {'user': user} - - -class Password(base.AuthConstructor): - """A plugin for authenticating with a username and password. - - :param string auth_url: Identity service endpoint for authentication. - :param string password: Password for authentication. - :param string username: Username for authentication. - :param string user_id: User ID for authentication. - :param string user_domain_id: User's domain ID for authentication. - :param string user_domain_name: User's domain name for authentication. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - _auth_method_class = PasswordMethod - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - - options.extend([ - cfg.StrOpt('user-id', help='User ID'), - cfg.StrOpt('username', dest='username', help='Username', - deprecated_name='user-name'), - cfg.StrOpt('user-domain-id', help="User's domain id"), - cfg.StrOpt('user-domain-name', help="User's domain name"), - cfg.StrOpt('password', secret=True, help="User's password"), - ]) - - return options - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - if not (kwargs.get('password') or namespace.os_password): - kwargs['password'] = utils.prompt_user_password() - - return super(Password, cls).load_from_argparse_arguments(namespace, - **kwargs) diff --git a/keystoneclient/auth/identity/v3/token.py b/keystoneclient/auth/identity/v3/token.py deleted file mode 100644 index 396a11a2..00000000 --- a/keystoneclient/auth/identity/v3/token.py +++ /dev/null @@ -1,65 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg - -from keystoneclient.auth.identity.v3 import base - - -__all__ = ('TokenMethod', 'Token') - - -class TokenMethod(base.AuthMethod): - """Construct an Auth plugin to fetch a token from a token. - - :param string token: Token for authentication. - """ - - _method_parameters = ['token'] - - def get_auth_data(self, session, auth, headers, **kwargs): - headers['X-Auth-Token'] = self.token - return 'token', {'id': self.token} - - -class Token(base.AuthConstructor): - """A plugin for authenticating with an existing Token. - - :param string auth_url: Identity service endpoint for authentication. - :param string token: Token for authentication. - :param string trust_id: Trust ID for trust scoping. - :param string domain_id: Domain ID for domain scoping. - :param string domain_name: Domain name for domain scoping. - :param string project_id: Project ID for project scoping. - :param string project_name: Project name for project scoping. - :param string project_domain_id: Project's domain ID for project. - :param string project_domain_name: Project's domain name for project. - :param bool reauthenticate: Allow fetching a new token if the current one - is going to expire. (optional) default True - """ - - _auth_method_class = TokenMethod - - def __init__(self, auth_url, token, **kwargs): - super(Token, self).__init__(auth_url, token=token, **kwargs) - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('token', - secret=True, - help='Token to authenticate with'), - ]) - - return options diff --git a/keystoneclient/auth/token_endpoint.py b/keystoneclient/auth/token_endpoint.py deleted file mode 100644 index 6b60f9cb..00000000 --- a/keystoneclient/auth/token_endpoint.py +++ /dev/null @@ -1,62 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import warnings - -from oslo_config import cfg - -from keystoneclient.auth import base - - -class Token(base.BaseAuthPlugin): - """A provider that will always use the given token and endpoint. - - This is really only useful for testing and in certain CLI cases where you - have a known endpoint and admin token that you want to use. - """ - - def __init__(self, endpoint, token): - # NOTE(jamielennox): endpoint is reserved for when plugins - # can be used to provide that information - warnings.warn( - 'TokenEndpoint plugin is deprecated as of the 2.1.0 release in ' - 'favor of keystoneauth1.token_endpoint.Token. It will be removed ' - 'in future releases.', - DeprecationWarning) - - self.endpoint = endpoint - self.token = token - - def get_token(self, session): - return self.token - - def get_endpoint(self, session, **kwargs): - """Return the supplied endpoint. - - Using this plugin the same endpoint is returned regardless of the - parameters passed to the plugin. - """ - return self.endpoint - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('endpoint', - help='The endpoint that will always be used'), - cfg.StrOpt('token', - secret=True, - help='The token that will always be used'), - ]) - - return options diff --git a/keystoneclient/base.py b/keystoneclient/base.py deleted file mode 100644 index 80e09a0e..00000000 --- a/keystoneclient/base.py +++ /dev/null @@ -1,549 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 OpenStack Foundation -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Base utilities to build API operation managers and objects on top of.""" - -import abc -import copy -import functools -import warnings - -from keystoneauth1 import exceptions as ksa_exceptions -from keystoneauth1 import plugin -from oslo_utils import strutils -import six -from six.moves import urllib - -from keystoneclient import exceptions as ksc_exceptions -from keystoneclient.i18n import _ - - -def getid(obj): - """Return id if argument is a Resource. - - Abstracts the common pattern of allowing both an object or an object's ID - (UUID) as a parameter when dealing with relationships. - """ - try: - if obj.uuid: - return obj.uuid - except AttributeError: # nosec(cjschaef): 'obj' doesn't contain attribute - # 'uuid', return attribute 'id' or the 'obj' - pass - try: - return obj.id - except AttributeError: - return obj - - -def filter_none(**kwargs): - """Remove any entries from a dictionary where the value is None.""" - return dict((k, v) for k, v in kwargs.items() if v is not None) - - -def filter_kwargs(f): - @functools.wraps(f) - def func(*args, **kwargs): - new_kwargs = {} - for key, ref in kwargs.items(): - if ref is None: - # drop null values - continue - - id_value = getid(ref) - if id_value != ref: - # If an object with an id was passed, then use the id, e.g.: - # user: user(id=1) becomes user_id: 1 - key = '%s_id' % key - - new_kwargs[key] = id_value - - return f(*args, **new_kwargs) - return func - - -class Manager(object): - """Basic manager type providing common operations. - - Managers interact with a particular type of API (servers, flavors, images, - etc.) and provide CRUD operations for them. - - :param client: instance of BaseClient descendant for HTTP requests - - """ - - resource_class = None - - def __init__(self, client): - super(Manager, self).__init__() - self.client = client - - @property - def api(self): - """The client. - - .. warning:: - - This property is deprecated as of the 1.7.0 release in favor of - :meth:`client` and may be removed in the 2.0.0 release. - - """ - warnings.warn( - 'api is deprecated as of the 1.7.0 release in favor of client and ' - 'may be removed in the 2.0.0 release', DeprecationWarning) - return self.client - - def _list(self, url, response_key, obj_class=None, body=None, **kwargs): - """List the collection. - - :param url: a partial URL, e.g., '/servers' - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param obj_class: class for constructing the returned objects - (self.resource_class will be used by default) - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param kwargs: Additional arguments will be passed to the request. - """ - if body: - resp, body = self.client.post(url, body=body, **kwargs) - else: - resp, body = self.client.get(url, **kwargs) - - if obj_class is None: - obj_class = self.resource_class - - data = body[response_key] - # NOTE(ja): keystone returns values as list as {'values': [ ... ]} - # unlike other services which just return the list... - try: - data = data['values'] - except (KeyError, TypeError): # nosec(cjschaef): keystone data values - # not as expected (see comment above), assumption is that values - # are already returned in a list (so simply utilize that list) - pass - - return [obj_class(self, res, loaded=True) for res in data if res] - - def _get(self, url, response_key, **kwargs): - """Get an object from collection. - - :param url: a partial URL, e.g., '/servers' - :param response_key: the key to be looked up in response dictionary, - e.g., 'server' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.get(url, **kwargs) - return self.resource_class(self, body[response_key], loaded=True) - - def _head(self, url, **kwargs): - """Retrieve request headers for an object. - - :param url: a partial URL, e.g., '/servers' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.head(url, **kwargs) - return resp.status_code == 204 - - def _post(self, url, body, response_key, return_raw=False, **kwargs): - """Create an object. - - :param url: a partial URL, e.g., '/servers' - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param return_raw: flag to force returning raw JSON instead of - Python object of self.resource_class - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.post(url, body=body, **kwargs) - if return_raw: - return body[response_key] - return self.resource_class(self, body[response_key]) - - def _put(self, url, body=None, response_key=None, **kwargs): - """Update an object with PUT method. - - :param url: a partial URL, e.g., '/servers' - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.put(url, body=body, **kwargs) - # PUT requests may not return a body - if body is not None: - if response_key is not None: - return self.resource_class(self, body[response_key]) - else: - return self.resource_class(self, body) - - def _patch(self, url, body=None, response_key=None, **kwargs): - """Update an object with PATCH method. - - :param url: a partial URL, e.g., '/servers' - :param body: data that will be encoded as JSON and passed in POST - request (GET will be sent by default) - :param response_key: the key to be looked up in response dictionary, - e.g., 'servers' - :param kwargs: Additional arguments will be passed to the request. - """ - resp, body = self.client.patch(url, body=body, **kwargs) - if response_key is not None: - return self.resource_class(self, body[response_key]) - else: - return self.resource_class(self, body) - - def _delete(self, url, **kwargs): - """Delete an object. - - :param url: a partial URL, e.g., '/servers/my-server' - :param kwargs: Additional arguments will be passed to the request. - """ - return self.client.delete(url, **kwargs) - - def _update(self, url, body=None, response_key=None, method="PUT", - **kwargs): - methods = {"PUT": self.client.put, - "POST": self.client.post, - "PATCH": self.client.patch} - try: - resp, body = methods[method](url, body=body, - **kwargs) - except KeyError: - raise ksc_exceptions.ClientException(_("Invalid update method: %s") - % method) - # PUT requests may not return a body - if body: - return self.resource_class(self, body[response_key]) - - -@six.add_metaclass(abc.ABCMeta) -class ManagerWithFind(Manager): - """Manager with additional `find()`/`findall()` methods.""" - - @abc.abstractmethod - def list(self): - pass # pragma: no cover - - def find(self, **kwargs): - """Find a single item with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - rl = self.findall(**kwargs) - num = len(rl) - - if num == 0: - msg = _("No %(name)s matching %(kwargs)s.") % { - 'name': self.resource_class.__name__, 'kwargs': kwargs} - raise ksa_exceptions.NotFound(404, msg) - elif num > 1: - raise ksc_exceptions.NoUniqueMatch - else: - return rl[0] - - def findall(self, **kwargs): - """Find all items with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - found = [] - searches = kwargs.items() - - for obj in self.list(): - try: - if all(getattr(obj, attr) == value - for (attr, value) in searches): - found.append(obj) - except AttributeError: - continue - - return found - - -class CrudManager(Manager): - """Base manager class for manipulating Keystone entities. - - Children of this class are expected to define a `collection_key` and `key`. - - - `collection_key`: Usually a plural noun by convention (e.g. `entities`); - used to refer collections in both URL's (e.g. `/v3/entities`) and JSON - objects containing a list of member resources (e.g. `{'entities': [{}, - {}, {}]}`). - - `key`: Usually a singular noun by convention (e.g. `entity`); used to - refer to an individual member of the collection. - - """ - - collection_key = None - key = None - base_url = None - - def build_url(self, dict_args_in_out=None): - """Build a resource URL for the given kwargs. - - Given an example collection where `collection_key = 'entities'` and - `key = 'entity'`, the following URL's could be generated. - - By default, the URL will represent a collection of entities, e.g.:: - - /entities - - If kwargs contains an `entity_id`, then the URL will represent a - specific member, e.g.:: - - /entities/{entity_id} - - If a `base_url` is provided, the generated URL will be appended to it. - - If a 'tail' is provided, it will be appended to the end of the URL. - - """ - if dict_args_in_out is None: - dict_args_in_out = {} - - url = dict_args_in_out.pop('base_url', None) or self.base_url or '' - url += '/%s' % self.collection_key - - # do we have a specific entity? - entity_id = dict_args_in_out.pop('%s_id' % self.key, None) - if entity_id is not None: - url += '/%s' % entity_id - - if dict_args_in_out.get('tail'): - url += dict_args_in_out['tail'] - - return url - - @filter_kwargs - def create(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - return self._post( - url, - {self.key: kwargs}, - self.key) - - @filter_kwargs - def get(self, **kwargs): - return self._get( - self.build_url(dict_args_in_out=kwargs), - self.key) - - @filter_kwargs - def head(self, **kwargs): - return self._head(self.build_url(dict_args_in_out=kwargs)) - - def _build_query(self, params): - if params is None: - return '' - else: - return '?%s' % urllib.parse.urlencode(params, doseq=True) - - def build_key_only_query(self, params_list): - """Build a query that does not include values, just keys. - - The Identity API has some calls that define queries without values, - this can not be accomplished by using urllib.parse.urlencode(). This - method builds a query using only the keys. - """ - return '?%s' % '&'.join(params_list) if params_list else '' - - @filter_kwargs - def list(self, fallback_to_auth=False, **kwargs): - if 'id' in kwargs.keys(): - # Ensure that users are not trying to call things like - # ``domains.list(id='default')`` when they should have used - # ``[domains.get(domain_id='default')]`` instead. Keystone supports - # ``GET /v3/domains/{domain_id}``, not ``GET - # /v3/domains?id={domain_id}``. - raise TypeError( - _("list() got an unexpected keyword argument 'id'. To " - "retrieve a single object using a globally unique " - "identifier, try using get() instead.")) - - url = self.build_url(dict_args_in_out=kwargs) - - try: - query = self._build_query(kwargs) - url_query = '%(url)s%(query)s' % {'url': url, 'query': query} - return self._list( - url_query, - self.collection_key) - except ksa_exceptions.EmptyCatalog: - if fallback_to_auth: - return self._list( - url_query, - self.collection_key, - endpoint_filter={'interface': plugin.AUTH_INTERFACE}) - else: - raise - - @filter_kwargs - def put(self, **kwargs): - return self._update( - self.build_url(dict_args_in_out=kwargs), - method='PUT') - - @filter_kwargs - def update(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - - return self._update( - url, - {self.key: kwargs}, - self.key, - method='PATCH') - - @filter_kwargs - def delete(self, **kwargs): - return self._delete( - self.build_url(dict_args_in_out=kwargs)) - - @filter_kwargs - def find(self, **kwargs): - """Find a single item with attributes matching ``**kwargs``.""" - url = self.build_url(dict_args_in_out=kwargs) - - query = self._build_query(kwargs) - url_query = '%(url)s%(query)s' % { - 'url': url, - 'query': query - } - elements = self._list( - url_query, - self.collection_key) - - if not elements: - msg = _("No %(name)s matching %(kwargs)s.") % { - 'name': self.resource_class.__name__, 'kwargs': kwargs} - raise ksa_exceptions.NotFound(404, msg) - elif len(elements) > 1: - raise ksc_exceptions.NoUniqueMatch - else: - return elements[0] - - -class Resource(object): - """Base class for OpenStack resources (tenant, user, etc.). - - This is pretty much just a bag for attributes. - """ - - HUMAN_ID = False - NAME_ATTR = 'name' - - def __init__(self, manager, info, loaded=False): - """Populate and bind to a manager. - - :param manager: BaseManager object - :param info: dictionary representing resource attributes - :param loaded: prevent lazy-loading if set to True - """ - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def __repr__(self): - """Return string representation of resource attributes.""" - reprkeys = sorted(k - for k in self.__dict__.keys() - if k[0] != '_' and k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - @property - def human_id(self): - """Human-readable ID which can be used for bash completion.""" - if self.HUMAN_ID: - name = getattr(self, self.NAME_ATTR, None) - if name is not None: - return strutils.to_slug(name) - return None - - def _add_details(self, info): - for (k, v) in info.items(): - try: - try: - setattr(self, k, v) - except UnicodeEncodeError: - # This happens when we're running with Python version that - # does not support Unicode identifiers (e.g. Python 2.7). - # In that case we can't help but not set this attrubute; - # it'll be available in a dict representation though - pass - self._info[k] = v - except AttributeError: # nosec(cjschaef): we already defined the - # attribute on the class - pass - - def __getattr__(self, k): - """Checking attrbiute existence.""" - if k not in self.__dict__: - # NOTE(bcwaldon): disallow lazy-loading if already loaded once - if not self.is_loaded(): - self.get() - return self.__getattr__(k) - - raise AttributeError(k) - else: - return self.__dict__[k] - - def get(self): - """Support for lazy loading details. - - Some clients, such as novaclient have the option to lazy load the - details, details which can be loaded with this function. - """ - # set_loaded() first ... so if we have to bail, we know we tried. - self.set_loaded(True) - if not hasattr(self.manager, 'get'): - return - - new = self.manager.get(self.id) - if new: - self._add_details(new._info) - - def __eq__(self, other): - """Define equality for resources.""" - if not isinstance(other, Resource): - return NotImplemented - # two resources of different types are not equal - if not isinstance(other, self.__class__): - return False - return self._info == other._info - - def __ne__(self, other): - """Define inequality for resources.""" - return not self == other - - def is_loaded(self): - return self._loaded - - def set_loaded(self, val): - self._loaded = val - - def to_dict(self): - return copy.deepcopy(self._info) - - def delete(self): - return self.manager.delete(self) diff --git a/keystoneclient/baseclient.py b/keystoneclient/baseclient.py deleted file mode 100644 index ca39f6d1..00000000 --- a/keystoneclient/baseclient.py +++ /dev/null @@ -1,46 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import warnings - - -class Client(object): - - def __init__(self, session): - warnings.warn( - 'keystoneclient.baseclient.Client is deprecated as of the 2.1.0 ' - 'release. It will be removed in future releases.', - DeprecationWarning) - - self.session = session - - def request(self, url, method, **kwargs): - kwargs.setdefault('authenticated', True) - return self.session.request(url, method, **kwargs) - - def get(self, url, **kwargs): - return self.request(url, 'GET', **kwargs) - - def head(self, url, **kwargs): - return self.request(url, 'HEAD', **kwargs) - - def post(self, url, **kwargs): - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - return self.request(url, 'PUT', **kwargs) - - def patch(self, url, **kwargs): - return self.request(url, 'PATCH', **kwargs) - - def delete(self, url, **kwargs): - return self.request(url, 'DELETE', **kwargs) diff --git a/keystoneclient/client.py b/keystoneclient/client.py deleted file mode 100644 index 5da9794d..00000000 --- a/keystoneclient/client.py +++ /dev/null @@ -1,63 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from debtcollector import removals - -from keystoneclient import discover -from keystoneclient import httpclient -from keystoneclient import session as client_session - - -@removals.remove(message='Use keystoneclient.httpclient.HTTPClient instead', - version='1.7.0', removal_version='2.0.0') -class HTTPClient(httpclient.HTTPClient): - """Deprecated alias for httpclient.HTTPClient. - - This class is deprecated as of the 1.7.0 release in favor of - :class:`keystoneclient.httpclient.HTTPClient` and may be removed in the - 2.0.0 release. - - """ - - -def Client(version=None, unstable=False, session=None, **kwargs): - """Factory function to create a new identity service client. - - The returned client will be either a V3 or V2 client. Check the version - using the :py:attr:`~keystoneclient.v3.client.Client.version` property or - the instance's class (with instanceof). - - :param tuple version: The required version of the identity API. If - specified the client will be selected such that the - major version is equivalent and an endpoint provides - at least the specified minor version. For example to - specify the 3.1 API use ``(3, 1)``. (optional) - :param bool unstable: Accept endpoints not marked as 'stable'. (optional) - :param session: A session object to be used for communication. If one is - not provided it will be constructed from the provided - kwargs. (optional) - :type session: keystoneclient.session.Session - :param kwargs: Additional arguments are passed through to the client - that is being created. - :returns: New keystone client object. - :rtype: :py:class:`keystoneclient.v3.client.Client` or - :py:class:`keystoneclient.v2_0.client.Client` - :raises keystoneclient.exceptions.DiscoveryFailure: if the server's - response is invalid. - :raises keystoneclient.exceptions.VersionNotAvailable: if a suitable client - cannot be found. - """ - if not session: - session = client_session.Session._construct(kwargs) - - d = discover.Discover(session=session, **kwargs) - return d.create_client(version=version, unstable=unstable) diff --git a/keystoneclient/common/__init__.py b/keystoneclient/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py deleted file mode 100644 index 9c3e0bdf..00000000 --- a/keystoneclient/common/cms.py +++ /dev/null @@ -1,444 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Certificate signing functions. - -Call set_subprocess() with the subprocess module. Either Python's -subprocess or eventlet.green.subprocess can be used. - -If set_subprocess() is not called, this module will pick Python's subprocess -or eventlet.green.subprocess based on if os module is patched by eventlet. -""" - -import base64 -import errno -import hashlib -import logging -import zlib - -from debtcollector import removals -import six - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -subprocess = None -LOG = logging.getLogger(__name__) -PKI_ASN1_PREFIX = 'MII' -PKIZ_PREFIX = 'PKIZ_' -PKIZ_CMS_FORM = 'DER' -PKI_ASN1_FORM = 'PEM' -DEFAULT_TOKEN_DIGEST_ALGORITHM = 'sha256' - - -# The openssl cms command exits with these status codes. -# See https://www.openssl.org/docs/man1.1.0/apps/cms.html#EXIT-CODES -class OpensslCmsExitStatus(object): - SUCCESS = 0 - COMMAND_OPTIONS_PARSING_ERROR = 1 - INPUT_FILE_READ_ERROR = 2 - CREATE_CMS_READ_MIME_ERROR = 3 - - -def _ensure_subprocess(): - # NOTE(vish): late loading subprocess so we can - # use the green version if we are in - # eventlet. - global subprocess - if not subprocess: - try: - from eventlet import patcher - if patcher.already_patched: - from eventlet.green import subprocess - else: - import subprocess # nosec(cjschaef): we must be careful when - # using subprocess.Popen with possibly untrusted data, - # assumption is that the certificate/key files provided are - # trustworthy - except ImportError: - import subprocess # noqa # nosec(cjschaef): we must be careful - # when using subprocess.Popen with possibly untrusted data, - # assumption is that the certificate/key files provided are - # trustworthy - - -def set_subprocess(_subprocess=None): - """Set subprocess module to use. - - The subprocess could be eventlet.green.subprocess if using eventlet, - or Python's subprocess otherwise. - """ - global subprocess - subprocess = _subprocess - - -def _check_files_accessible(files): - err = None - retcode = -1 - try: - for try_file in files: - with open(try_file, 'r'): - pass - except IOError as e: - # Catching IOError means there is an issue with - # the given file. - err = try_file, e.strerror - # Emulate openssl behavior, which returns with code 2 when - # access to a file failed. - retcode = OpensslCmsExitStatus.INPUT_FILE_READ_ERROR - - return retcode, err - - -def _process_communicate_handle_oserror(process, data, files): - """Wrapper around process.communicate that checks for OSError.""" - try: - output, err = process.communicate(data) - except OSError as e: - if e.errno != errno.EPIPE: - raise - # OSError with EPIPE only occurs with old Python 2.7.x versions - # http://bugs.python.org/issue10963 - - # The quick exit is typically caused by the openssl command not being - # able to read an input file, so check ourselves if can't read a file. - retcode, err = _check_files_accessible(files) - if process.stderr: - msg = process.stderr.read() - if isinstance(msg, six.binary_type): - msg = msg.decode('utf-8') - if err: - err = (_('Hit OSError in ' - '_process_communicate_handle_oserror(): ' - '%(stderr)s\nLikely due to %(file)s: %(error)s') % - {'stderr': msg, - 'file': err[0], - 'error': err[1]}) - else: - err = (_('Hit OSError in ' - '_process_communicate_handle_oserror(): %s') % msg) - - output = '' - else: - retcode = process.poll() - if err is not None: - if isinstance(err, six.binary_type): - err = err.decode('utf-8') - - return output, err, retcode - - -def _encoding_for_form(inform): - if inform == PKI_ASN1_FORM: - encoding = 'UTF-8' - elif inform == PKIZ_CMS_FORM: - encoding = 'hex' - else: - raise ValueError( - _('"inform" must be one of: %s') % ','.join((PKI_ASN1_FORM, - PKIZ_CMS_FORM))) - - return encoding - - -def cms_verify(formatted, signing_cert_file_name, ca_file_name, - inform=PKI_ASN1_FORM): - """Verify the signature of the contents IAW CMS syntax. - - :raises subprocess.CalledProcessError: - :raises keystoneclient.exceptions.CertificateConfigError: if certificate - is not configured - properly. - """ - _ensure_subprocess() - if isinstance(formatted, six.string_types): - data = bytearray(formatted, _encoding_for_form(inform)) - else: - data = formatted - process = subprocess.Popen(['openssl', 'cms', '-verify', - '-certfile', signing_cert_file_name, - '-CAfile', ca_file_name, - '-inform', 'PEM', - '-nosmimecap', '-nodetach', - '-nocerts', '-noattr'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) - output, err, retcode = _process_communicate_handle_oserror( - process, data, (signing_cert_file_name, ca_file_name)) - - # Do not log errors, as some happen in the positive thread - # instead, catch them in the calling code and log them there. - - # When invoke the openssl >= 1.1.0 with not exist file, return code should - # be 2 instead of 1 and error msg will be returned. - # You can get more from - # https://www.openssl.org/docs/man1.1.0/apps/cms.html#EXIT-CODES - # - # $ openssl cms -verify -certfile not_exist_file -CAfile - # not_exist_file -inform PEM -nosmimecap -nodetach - # -nocerts -noattr - # openssl < 1.1.0 returns - # Error opening certificate file not_exist_file - # openssl >= 1.1.0 returns - # cms: Cannot open input file not_exist_file, No such file or directory - # - if retcode == OpensslCmsExitStatus.INPUT_FILE_READ_ERROR: - if err.startswith('Error reading S/MIME message'): - raise exceptions.CMSError(err) - else: - raise exceptions.CertificateConfigError(err) - # workaround for OpenSSL >= 1.1.0, - # should return OpensslCmsExitStatus.INPUT_FILE_READ_ERROR - elif retcode == OpensslCmsExitStatus.COMMAND_OPTIONS_PARSING_ERROR: - if err.startswith('cms: Cannot open input file'): - raise exceptions.CertificateConfigError(err) - else: - raise subprocess.CalledProcessError(retcode, 'openssl', output=err) - elif retcode != OpensslCmsExitStatus.SUCCESS: - raise subprocess.CalledProcessError(retcode, 'openssl', output=err) - return output - - -def is_pkiz(token_text): - """Determine if a token is PKIZ. - - Checks if the string has the prefix that indicates it is a - Crypto Message Syntax, Z compressed token. - """ - return token_text.startswith(PKIZ_PREFIX) - - -def pkiz_sign(text, - signing_cert_file_name, - signing_key_file_name, - compression_level=6, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - signed = cms_sign_data(text, - signing_cert_file_name, - signing_key_file_name, - PKIZ_CMS_FORM, - message_digest=message_digest) - - compressed = zlib.compress(signed, compression_level) - encoded = PKIZ_PREFIX + base64.urlsafe_b64encode( - compressed).decode('utf-8') - return encoded - - -def pkiz_uncompress(signed_text): - text = signed_text[len(PKIZ_PREFIX):].encode('utf-8') - unencoded = base64.urlsafe_b64decode(text) - uncompressed = zlib.decompress(unencoded) - return uncompressed - - -def pkiz_verify(signed_text, signing_cert_file_name, ca_file_name): - uncompressed = pkiz_uncompress(signed_text) - return cms_verify(uncompressed, signing_cert_file_name, ca_file_name, - inform=PKIZ_CMS_FORM) - - -def token_to_cms(signed_text): - """Convert a custom formatted token to a PEM-formatted token. - - See documentation for cms_to_token() for details on the custom formatting. - """ - copy_of_text = signed_text.replace('-', '/') - - lines = ['-----BEGIN CMS-----'] - lines += [copy_of_text[n:n + 64] for n in range(0, len(copy_of_text), 64)] - lines.append('-----END CMS-----\n') - return '\n'.join(lines) - - -def verify_token(token, signing_cert_file_name, ca_file_name): - return cms_verify(token_to_cms(token), - signing_cert_file_name, - ca_file_name) - - -def is_asn1_token(token): - """Determine if a token appears to be PKI-based. - - thx to ayoung for sorting this out. - - base64 decoded hex representation of MII is 3082:: - - In [3]: binascii.hexlify(base64.b64decode('MII=')) - Out[3]: '3082' - - re: http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf - - :: - - pg4: For tags from 0 to 30 the first octet is the identfier - pg10: Hex 30 means sequence, followed by the length of that sequence. - pg5: Second octet is the length octet - first bit indicates short or long form, next 7 bits encode the - number of subsequent octets that make up the content length octets - as an unsigned binary int - - 82 = 10000010 (first bit indicates long form) - 0000010 = 2 octets of content length - so read the next 2 octets to get the length of the content. - - In the case of a very large content length there could be a requirement to - have more than 2 octets to designate the content length, therefore - requiring us to check for MIM, MIQ, etc. - - :: - - In [4]: base64.b64encode(binascii.a2b_hex('3083')) - Out[4]: 'MIM=' - In [5]: base64.b64encode(binascii.a2b_hex('3084')) - Out[5]: 'MIQ=' - Checking for MI would become invalid at 16 octets of content length - 10010000 = 90 - In [6]: base64.b64encode(binascii.a2b_hex('3090')) - Out[6]: 'MJA=' - Checking for just M is insufficient - - But we will only check for MII: - Max length of the content using 2 octets is 3FFF or 16383. - - It's not practical to support a token of this length or greater in http - therefore, we will check for MII only and ignore the case of larger tokens - """ - return token[:3] == PKI_ASN1_PREFIX - - -@removals.remove(message='Use is_asn1_token() instead.', version='1.7.0', - removal_version='2.0.0') -def is_ans1_token(token): - """Deprecated. - - This function is deprecated as of the 1.7.0 release in favor of - :func:`is_asn1_token` and may be removed in the 2.0.0 release. - """ - return is_asn1_token(token) - - -def cms_sign_text(data_to_sign, signing_cert_file_name, signing_key_file_name, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - return cms_sign_data(data_to_sign, signing_cert_file_name, - signing_key_file_name, message_digest=message_digest) - - -def cms_sign_data(data_to_sign, signing_cert_file_name, signing_key_file_name, - outform=PKI_ASN1_FORM, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - """Use OpenSSL to sign a document. - - Produces a Base64 encoding of a DER formatted CMS Document - http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax - - :param data_to_sign: data to sign - :param signing_cert_file_name: path to the X509 certificate containing - the public key associated with the private key used to sign the data - :param signing_key_file_name: path to the private key used to sign - the data - :param outform: Format for the signed document PKIZ_CMS_FORM or - PKI_ASN1_FORM - :param message_digest: Digest algorithm to use when signing or resigning - - """ - _ensure_subprocess() - if isinstance(data_to_sign, six.string_types): - data = bytearray(data_to_sign, encoding='utf-8') - else: - data = data_to_sign - process = subprocess.Popen(['openssl', 'cms', '-sign', - '-signer', signing_cert_file_name, - '-inkey', signing_key_file_name, - '-outform', 'PEM', - '-nosmimecap', '-nodetach', - '-nocerts', '-noattr', - '-md', message_digest, ], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) - - output, err, retcode = _process_communicate_handle_oserror( - process, data, (signing_cert_file_name, signing_key_file_name)) - - if retcode != OpensslCmsExitStatus.SUCCESS or ('Error' in err): - if retcode == OpensslCmsExitStatus.CREATE_CMS_READ_MIME_ERROR: - LOG.error('Signing error: Unable to load certificate - ' - 'ensure you have configured PKI with ' - '"keystone-manage pki_setup"') - else: - LOG.error('Signing error: %s', err) - raise subprocess.CalledProcessError(retcode, 'openssl') - if outform == PKI_ASN1_FORM: - return output.decode('utf-8') - else: - return output - - -def cms_sign_token(text, signing_cert_file_name, signing_key_file_name, - message_digest=DEFAULT_TOKEN_DIGEST_ALGORITHM): - output = cms_sign_data(text, signing_cert_file_name, signing_key_file_name, - message_digest=message_digest) - return cms_to_token(output) - - -def cms_to_token(cms_text): - """Convert a CMS-signed token in PEM format to a custom URL-safe format. - - The conversion consists of replacing '/' char in the PEM-formatted token - with the '-' char and doing other such textual replacements to make the - result marshallable via HTTP. The return value can thus be used as the - value of a HTTP header such as "X-Auth-Token". - - This ad-hoc conversion is an unfortunate oversight since the returned - value now does not conform to any of the standard variants of base64 - encoding. It would have been better to use base64url encoding (either on - the PEM formatted text or, perhaps even better, on the inner CMS-signed - binary value without any PEM formatting). In any case, the same conversion - is done in reverse in the other direction (for token verification), so - there are no correctness issues here. Note that the non-standard encoding - of the token will be preserved so as to not break backward compatibility. - - The conversion issue is detailed by the code author in a blog post at - http://adam.younglogic.com/2014/02/compressed-tokens/. - """ - start_delim = '-----BEGIN CMS-----' - end_delim = '-----END CMS-----' - signed_text = cms_text - signed_text = signed_text.replace('/', '-') - signed_text = signed_text.replace(start_delim, '') - signed_text = signed_text.replace(end_delim, '') - signed_text = signed_text.replace('\n', '') - - return signed_text - - -def cms_hash_token(token_id, mode='md5'): - """Hash PKI tokens. - - return: for asn1 or pkiz tokens, returns the hash of the passed in token - otherwise, returns what it was passed in. - """ - if token_id is None: - return None - if is_asn1_token(token_id) or is_pkiz(token_id): - hasher = hashlib.new(mode) - if isinstance(token_id, six.text_type): - token_id = token_id.encode('utf-8') - hasher.update(token_id) - return hasher.hexdigest() - else: - return token_id diff --git a/keystoneclient/contrib/__init__.py b/keystoneclient/contrib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/auth/__init__.py b/keystoneclient/contrib/auth/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/auth/v3/__init__.py b/keystoneclient/contrib/auth/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/auth/v3/oidc.py b/keystoneclient/contrib/auth/v3/oidc.py deleted file mode 100644 index 957c50e4..00000000 --- a/keystoneclient/contrib/auth/v3/oidc.py +++ /dev/null @@ -1,211 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg -from positional import positional - -from keystoneclient import access -from keystoneclient.auth.identity.v3 import federated - - -class OidcPassword(federated.FederatedBaseAuth): - """Implement authentication plugin for OpenID Connect protocol. - - OIDC or OpenID Connect is a protocol for federated authentication. - - The OpenID Connect specification can be found at:: - ``http://openid.net/specs/openid-connect-core-1_0.html`` - """ - - @classmethod - def get_options(cls): - options = super(OidcPassword, cls).get_options() - options.extend([ - cfg.StrOpt('username', help='Username'), - cfg.StrOpt('password', secret=True, help='Password'), - cfg.StrOpt('client-id', help='OAuth 2.0 Client ID'), - cfg.StrOpt('client-secret', secret=True, - help='OAuth 2.0 Client Secret'), - cfg.StrOpt('access-token-endpoint', - help='OpenID Connect Provider Token Endpoint'), - cfg.StrOpt('scope', default="profile", - help='OpenID Connect scope that is requested from OP') - ]) - return options - - @positional(4) - def __init__(self, auth_url, identity_provider, protocol, - username, password, client_id, client_secret, - access_token_endpoint, scope='profile', - grant_type='password'): - """The OpenID Connect plugin. - - It expects the following: - - :param auth_url: URL of the Identity Service - :type auth_url: string - - :param identity_provider: Name of the Identity Provider the client - will authenticate against - :type identity_provider: string - - :param protocol: Protocol name as configured in keystone - :type protocol: string - - :param username: Username used to authenticate - :type username: string - - :param password: Password used to authenticate - :type password: string - - :param client_id: OAuth 2.0 Client ID - :type client_id: string - - :param client_secret: OAuth 2.0 Client Secret - :type client_secret: string - - :param access_token_endpoint: OpenID Connect Provider Token Endpoint, - for example: - https://localhost:8020/oidc/OP/token - :type access_token_endpoint: string - - :param scope: OpenID Connect scope that is requested from OP, - defaults to "profile", for example: "profile email" - :type scope: string - - :param grant_type: OpenID Connect grant type, it represents the flow - that is used to talk to the OP. Valid values are: - "authorization_code", "refresh_token", or - "password". - :type grant_type: string - """ - super(OidcPassword, self).__init__(auth_url, identity_provider, - protocol) - self._username = username - self._password = password - self.client_id = client_id - self.client_secret = client_secret - self.access_token_endpoint = access_token_endpoint - self.scope = scope - self.grant_type = grant_type - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - def get_unscoped_auth_ref(self, session): - """Authenticate with OpenID Connect and get back claims. - - This is a multi-step process. First an access token must be retrieved, - to do this, the username and password, the OpenID Connect client ID - and secret, and the access token endpoint must be known. - - Secondly, we then exchange the access token upon accessing the - protected Keystone endpoint (federated auth URL). This will trigger - the OpenID Connect Provider to perform a user introspection and - retrieve information (specified in the scope) about the user in - the form of an OpenID Connect Claim. These claims will be sent - to Keystone in the form of environment variables. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: a token data representation - :rtype: :py:class:`keystoneclient.access.AccessInfo` - """ - # get an access token - client_auth = (self.client_id, self.client_secret) - payload = {'grant_type': self.grant_type, 'username': self.username, - 'password': self.password, 'scope': self.scope} - response = self._get_access_token(session, client_auth, payload, - self.access_token_endpoint) - access_token = response.json()['access_token'] - - # use access token against protected URL - headers = {'Authorization': 'Bearer ' + access_token} - response = self._get_keystone_token(session, headers, - self.federated_token_url) - - # grab the unscoped token - token = response.headers['X-Subject-Token'] - token_json = response.json()['token'] - return access.AccessInfoV3(token, **token_json) - - def _get_access_token(self, session, client_auth, payload, - access_token_endpoint): - """Exchange a variety of user supplied values for an access token. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :param client_auth: a tuple representing client id and secret - :type client_auth: tuple - - :param payload: a dict containing various OpenID Connect values, for - example:: - {'grant_type': 'password', 'username': self.username, - 'password': self.password, 'scope': self.scope} - :type payload: dict - - :param access_token_endpoint: URL to use to get an access token, for - example: https://localhost/oidc/token - :type access_token_endpoint: string - """ - op_response = session.post(self.access_token_endpoint, - requests_auth=client_auth, - data=payload, - authenticated=False) - return op_response - - def _get_keystone_token(self, session, headers, federated_token_url): - r"""Exchange an acess token for a keystone token. - - By Sending the access token in an `Authorization: Bearer` header, to - an OpenID Connect protected endpoint (Federated Token URL). The - OpenID Connect server will use the access token to look up information - about the authenticated user (this technique is called instrospection). - The output of the instrospection will be an OpenID Connect Claim, that - will be used against the mapping engine. Should the mapping engine - succeed, a Keystone token will be presented to the user. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :param headers: an Authorization header containing the access token. - :type headers_: dict - - :param federated_auth_url: Protected URL for federated authentication, - for example: https://localhost:5000/v3/\ - OS-FEDERATION/identity_providers/bluepages/\ - protocols/oidc/auth - :type federated_auth_url: string - """ - auth_response = session.post(self.federated_token_url, - headers=headers, - authenticated=False) - return auth_response diff --git a/keystoneclient/contrib/auth/v3/saml2.py b/keystoneclient/contrib/auth/v3/saml2.py deleted file mode 100644 index 8a07b7f3..00000000 --- a/keystoneclient/contrib/auth/v3/saml2.py +++ /dev/null @@ -1,920 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime -import uuid - -from lxml import etree # nosec(cjschaef): used to create xml, not parse it -from oslo_config import cfg -from six.moves import urllib - -from keystoneclient import access -from keystoneclient.auth.identity import v3 -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class _BaseSAMLPlugin(v3.AuthConstructor): - - HTTP_MOVED_TEMPORARILY = 302 - HTTP_SEE_OTHER = 303 - - PROTOCOL = 'saml2' - - @staticmethod - def _first(_list): - if len(_list) != 1: - raise IndexError(_("Only single element list is acceptable")) - return _list[0] - - @staticmethod - def str_to_xml(content, msg=None, include_exc=True): - try: - return etree.XML(content) - except etree.XMLSyntaxError as e: - if not msg: - msg = str(e) - else: - msg = msg % e if include_exc else msg - raise exceptions.AuthorizationFailure(msg) - - @staticmethod - def xml_to_str(content, **kwargs): - return etree.tostring(content, **kwargs) - - @property - def token_url(self): - """Return full URL where authorization data is sent.""" - values = { - 'host': self.auth_url.rstrip('/'), - 'identity_provider': self.identity_provider, - 'protocol': self.PROTOCOL - } - url = ("%(host)s/OS-FEDERATION/identity_providers/" - "%(identity_provider)s/protocols/%(protocol)s/auth") - url = url % values - - return url - - @classmethod - def get_options(cls): - options = super(_BaseSAMLPlugin, cls).get_options() - options.extend([ - cfg.StrOpt('identity-provider', help="Identity Provider's name"), - cfg.StrOpt('identity-provider-url', - help="Identity Provider's URL"), - cfg.StrOpt('username', dest='username', help='Username', - deprecated_name='user-name'), - cfg.StrOpt('password', secret=True, help='Password') - ]) - return options - - -class Saml2UnscopedTokenAuthMethod(v3.AuthMethod): - _method_parameters = [] - - def get_auth_data(self, session, auth, headers, **kwargs): - raise exceptions.MethodNotImplemented(_('This method should never ' - 'be called')) - - -class Saml2UnscopedToken(_BaseSAMLPlugin): - r"""Implement authentication plugin for SAML2 protocol. - - ECP stands for `Enhanced Client or Proxy` and is a SAML2 extension - for federated authentication where a transportation layer consists of - HTTP protocol and XML SOAP messages. - - `Read for more information - `_ on ECP. - - Reference the `SAML2 ECP specification `_. - - Currently only HTTPBasicAuth mechanism is available for the IdP - authenication. - - :param auth_url: URL of the Identity Service - :type auth_url: string - - :param identity_provider: name of the Identity Provider the client will - authenticate against. This parameter will be used - to build a dynamic URL used to obtain unscoped - OpenStack token. - :type identity_provider: string - - :param identity_provider_url: An Identity Provider URL, where the SAML2 - authn request will be sent. - :type identity_provider_url: string - - :param username: User's login - :type username: string - - :param password: User's password - :type password: string - - """ - - _auth_method_class = Saml2UnscopedTokenAuthMethod - - SAML2_HEADER_INDEX = 0 - ECP_SP_EMPTY_REQUEST_HEADERS = { - 'Accept': 'text/html, application/vnd.paos+xml', - 'PAOS': ('ver="urn:liberty:paos:2003-08";"urn:oasis:names:tc:' - 'SAML:2.0:profiles:SSO:ecp"') - } - - ECP_SP_SAML2_REQUEST_HEADERS = { - 'Content-Type': 'application/vnd.paos+xml' - } - - ECP_SAML2_NAMESPACES = { - 'ecp': 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp', - 'S': 'http://schemas.xmlsoap.org/soap/envelope/', - 'paos': 'urn:liberty:paos:2003-08' - } - - ECP_RELAY_STATE = '//ecp:RelayState' - - ECP_SERVICE_PROVIDER_CONSUMER_URL = ('/S:Envelope/S:Header/paos:Request/' - '@responseConsumerURL') - - ECP_IDP_CONSUMER_URL = ('/S:Envelope/S:Header/ecp:Response/' - '@AssertionConsumerServiceURL') - - SOAP_FAULT = """ - - - - S:Server - responseConsumerURL from SP and - assertionConsumerServiceURL from IdP do not match - - - - - """ - - def __init__(self, auth_url, - identity_provider, - identity_provider_url, - username, password, - **kwargs): - super(Saml2UnscopedToken, self).__init__(auth_url=auth_url, **kwargs) - self.identity_provider = identity_provider - self.identity_provider_url = identity_provider_url - self._username, self._password = username, password - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - def _handle_http_ecp_redirect(self, session, response, method, **kwargs): - if response.status_code not in (self.HTTP_MOVED_TEMPORARILY, - self.HTTP_SEE_OTHER): - return response - - location = response.headers['location'] - return session.request(location, method, authenticated=False, - **kwargs) - - def _prepare_idp_saml2_request(self, saml2_authn_request): - header = saml2_authn_request[self.SAML2_HEADER_INDEX] - saml2_authn_request.remove(header) - - def _check_consumer_urls(self, session, sp_response_consumer_url, - idp_sp_response_consumer_url): - """Check if consumer URLs issued by SP and IdP are equal. - - In the initial SAML2 authn Request issued by a Service Provider - there is a url called ``consumer url``. A trusted Identity Provider - should issue identical url. If the URLs are not equal the federated - authn process should be interrupted and the user should be warned. - - :param session: session object to send out HTTP requests. - :type session: keystoneclient.session.Session - :param sp_response_consumer_url: consumer URL issued by a SP - :type sp_response_consumer_url: string - :param idp_sp_response_consumer_url: consumer URL issued by an IdP - :type idp_sp_response_consumer_url: string - - """ - if sp_response_consumer_url != idp_sp_response_consumer_url: - # send fault message to the SP, discard the response - session.post(sp_response_consumer_url, data=self.SOAP_FAULT, - headers=self.ECP_SP_SAML2_REQUEST_HEADERS, - authenticated=False) - - # prepare error message and raise an exception. - msg = _("Consumer URLs from Service Provider %(service_provider)s " - "%(sp_consumer_url)s and Identity Provider " - "%(identity_provider)s %(idp_consumer_url)s are not equal") - msg = msg % { - 'service_provider': self.token_url, - 'sp_consumer_url': sp_response_consumer_url, - 'identity_provider': self.identity_provider, - 'idp_consumer_url': idp_sp_response_consumer_url - } - - raise exceptions.ValidationError(msg) - - def _send_service_provider_request(self, session): - """Initial HTTP GET request to the SAML2 protected endpoint. - - It's crucial to include HTTP headers indicating that the client is - willing to take advantage of the ECP SAML2 extension and receive data - as the SOAP. - Unlike standard authentication methods in the OpenStack Identity, - the client accesses:: - ``/v3/OS-FEDERATION/identity_providers/{identity_providers}/ - protocols/{protocol}/auth`` - - After a successful HTTP call the HTTP response should include SAML2 - authn request in the XML format. - - If a HTTP response contains ``X-Subject-Token`` in the headers and - the response body is a valid JSON assume the user was already - authenticated and Keystone returned a valid unscoped token. - Return True indicating the user was already authenticated. - - :param session: a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - """ - sp_response = session.get(self.token_url, - headers=self.ECP_SP_EMPTY_REQUEST_HEADERS, - authenticated=False) - - if 'X-Subject-Token' in sp_response.headers: - self.authenticated_response = sp_response - return True - - try: - self.saml2_authn_request = etree.XML(sp_response.content) - except etree.XMLSyntaxError as e: - msg = _("SAML2: Error parsing XML returned " - "from Service Provider, reason: %s") % e - raise exceptions.AuthorizationFailure(msg) - - relay_state = self.saml2_authn_request.xpath( - self.ECP_RELAY_STATE, namespaces=self.ECP_SAML2_NAMESPACES) - self.relay_state = self._first(relay_state) - - sp_response_consumer_url = self.saml2_authn_request.xpath( - self.ECP_SERVICE_PROVIDER_CONSUMER_URL, - namespaces=self.ECP_SAML2_NAMESPACES) - self.sp_response_consumer_url = self._first(sp_response_consumer_url) - return False - - def _send_idp_saml2_authn_request(self, session): - """Present modified SAML2 authn assertion from the Service Provider.""" - self._prepare_idp_saml2_request(self.saml2_authn_request) - idp_saml2_authn_request = self.saml2_authn_request - - # Currently HTTPBasicAuth method is hardcoded into the plugin - idp_response = session.post( - self.identity_provider_url, - headers={'Content-type': 'text/xml'}, - data=etree.tostring(idp_saml2_authn_request), - requests_auth=(self.username, self.password), - authenticated=False, log=False) - - try: - self.saml2_idp_authn_response = etree.XML(idp_response.content) - except etree.XMLSyntaxError as e: - msg = _("SAML2: Error parsing XML returned " - "from Identity Provider, reason: %s") % e - raise exceptions.AuthorizationFailure(msg) - - idp_response_consumer_url = self.saml2_idp_authn_response.xpath( - self.ECP_IDP_CONSUMER_URL, - namespaces=self.ECP_SAML2_NAMESPACES) - - self.idp_response_consumer_url = self._first(idp_response_consumer_url) - - self._check_consumer_urls(session, self.idp_response_consumer_url, - self.sp_response_consumer_url) - - def _send_service_provider_saml2_authn_response(self, session): - """Present SAML2 assertion to the Service Provider. - - The assertion is issued by a trusted Identity Provider for the - authenticated user. This function directs the HTTP request to SP - managed URL, for instance: ``https://:/Shibboleth.sso/ - SAML2/ECP``. - Upon success the there's a session created and access to the protected - resource is granted. Many implementations of the SP return HTTP 302/303 - status code pointing to the protected URL (``https://:/v3/ - OS-FEDERATION/identity_providers/{identity_provider}/protocols/ - {protocol_id}/auth`` in this case). Saml2 plugin should point to that - URL again, with HTTP GET method, expecting an unscoped token. - - :param session: a session object to send out HTTP requests. - - """ - self.saml2_idp_authn_response[0][0] = self.relay_state - - response = session.post( - self.idp_response_consumer_url, - headers=self.ECP_SP_SAML2_REQUEST_HEADERS, - data=etree.tostring(self.saml2_idp_authn_response), - authenticated=False, redirect=False) - - # Don't follow HTTP specs - after the HTTP 302/303 response don't - # repeat the call directed to the Location URL. In this case, this is - # an indication that saml2 session is now active and protected resource - # can be accessed. - response = self._handle_http_ecp_redirect( - session, response, method='GET', - headers=self.ECP_SP_SAML2_REQUEST_HEADERS) - - self.authenticated_response = response - - def _get_unscoped_token(self, session): - """Get unscoped OpenStack token after federated authentication. - - This is a multi-step process including multiple HTTP requests. - - The federated authentication consists of:: - * HTTP GET request to the Identity Service (acting as a Service - Provider). Client utilizes URL:: - ``/v3/OS-FEDERATION/identity_providers/{identity_provider}/ - protocols/saml2/auth``. - It's crucial to include HTTP headers indicating we are expecting - SOAP message in return. - Service Provider should respond with such SOAP message. - This step is handed by a method - ``Saml2UnscopedToken_send_service_provider_request()`` - - * HTTP POST request to the external Identity Provider service with - ECP extension enabled. The content sent is a header removed SOAP - message returned from the Service Provider. It's also worth noting - that ECP extension to the SAML2 doesn't define authentication method. - The most popular is HttpBasicAuth with just user and password. - Other possibilities could be X509 certificates or Kerberos. - Upon successful authentication the user should receive a SAML2 - assertion. - This step is handed by a method - ``Saml2UnscopedToken_send_idp_saml2_authn_request(session)`` - - * HTTP POST request again to the Service Provider. The body of the - request includes SAML2 assertion issued by a trusted Identity - Provider. The request should be sent to the Service Provider - consumer url specified in the SAML2 assertion. - Providing the authentication was successful and both Service Provider - and Identity Providers are trusted to each other, the Service - Provider will issue an unscoped token with a list of groups the - federated user is a member of. - This step is handed by a method - ``Saml2UnscopedToken_send_service_provider_saml2_authn_response()`` - - Unscoped token example:: - - { - "token": { - "methods": [ - "saml2" - ], - "user": { - "id": "username%40example.com", - "name": "username@example.com", - "OS-FEDERATION": { - "identity_provider": "ACME", - "protocol": "saml2", - "groups": [ - {"id": "abc123"}, - {"id": "bcd234"} - ] - } - } - } - } - - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: (token, token_json) - - """ - saml_authenticated = self._send_service_provider_request(session) - if not saml_authenticated: - self._send_idp_saml2_authn_request(session) - self._send_service_provider_saml2_authn_response(session) - return (self.authenticated_response.headers['X-Subject-Token'], - self.authenticated_response.json()['token']) - - def get_auth_ref(self, session, **kwargs): - """Authenticate via SAML2 protocol and retrieve unscoped token. - - This is a multi-step process where a client does federated authn - receives an unscoped token. - - Federated authentication utilizing SAML2 Enhanced Client or Proxy - extension. See ``Saml2UnscopedToken_get_unscoped_token()`` - for more information on that step. - Upon successful authentication and assertion mapping an - unscoped token is returned and stored within the plugin object for - further use. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :return: an object with scoped token's id and unscoped token json - included. - :rtype: :py:class:`keystoneclient.access.AccessInfoV3` - - """ - token, token_json = self._get_unscoped_token(session) - return access.AccessInfoV3(token, - **token_json) - - -class ADFSUnscopedToken(_BaseSAMLPlugin): - """Authentication plugin for Microsoft ADFS2.0 IdPs. - - :param auth_url: URL of the Identity Service - :type auth_url: string - - :param identity_provider: name of the Identity Provider the client will - authenticate against. This parameter will be used - to build a dynamic URL used to obtain unscoped - OpenStack token. - :type identity_provider: string - - :param identity_provider_url: An Identity Provider URL, where the SAML2 - authentication request will be sent. - :type identity_provider_url: string - - :param service_provider_endpoint: Endpoint where an assertion is being - sent, for instance: ``https://host.domain/Shibboleth.sso/ADFS`` - :type service_provider_endpoint: string - - :param username: User's login - :type username: string - - :param password: User's password - :type password: string - - """ - - _auth_method_class = Saml2UnscopedTokenAuthMethod - - DEFAULT_ADFS_TOKEN_EXPIRATION = 120 - - HEADER_SOAP = {"Content-Type": "application/soap+xml; charset=utf-8"} - HEADER_X_FORM = {"Content-Type": "application/x-www-form-urlencoded"} - - NAMESPACES = { - 's': 'http://www.w3.org/2003/05/soap-envelope', - 'a': 'http://www.w3.org/2005/08/addressing', - 'u': ('http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd') - } - - ADFS_TOKEN_NAMESPACES = { - 's': 'http://www.w3.org/2003/05/soap-envelope', - 't': 'http://docs.oasis-open.org/ws-sx/ws-trust/200512' - } - ADFS_ASSERTION_XPATH = ('/s:Envelope/s:Body' - '/t:RequestSecurityTokenResponseCollection' - '/t:RequestSecurityTokenResponse') - - def __init__(self, auth_url, identity_provider, identity_provider_url, - service_provider_endpoint, username, password, **kwargs): - super(ADFSUnscopedToken, self).__init__(auth_url=auth_url, **kwargs) - self.identity_provider = identity_provider - self.identity_provider_url = identity_provider_url - self.service_provider_endpoint = service_provider_endpoint - self._username, self._password = username, password - - @property - def username(self): - # Override to remove deprecation. - return self._username - - @username.setter - def username(self, value): - # Override to remove deprecation. - self._username = value - - @property - def password(self): - # Override to remove deprecation. - return self._password - - @password.setter - def password(self, value): - # Override to remove deprecation. - self._password = value - - @classmethod - def get_options(cls): - options = super(ADFSUnscopedToken, cls).get_options() - - options.extend([ - cfg.StrOpt('service-provider-endpoint', - help="Service Provider's Endpoint") - ]) - return options - - def _cookies(self, session): - """Check if cookie jar is not empty. - - keystoneclient.session.Session object doesn't have a cookies attribute. - We should then try fetching cookies from the underlying - requests.Session object. If that fails too, there is something wrong - and let Python raise the AttributeError. - - :param session - :returns: True if cookie jar is nonempty, False otherwise - :raises AttributeError: in case cookies are not find anywhere - - """ - try: - return bool(session.cookies) - except AttributeError: # nosec(cjschaef): fetch cookies from - # underylying requests.Session object, or fail trying - pass - - return bool(session.session.cookies) - - def _token_dates(self, fmt='%Y-%m-%dT%H:%M:%S.%fZ'): - """Calculate created and expires datetime objects. - - The method is going to be used for building ADFS Request Security - Token message. Time interval between ``created`` and ``expires`` - dates is now static and equals to 120 seconds. ADFS security tokens - should not be live too long, as currently ``keystoneclient`` - doesn't have mechanisms for reusing such tokens (every time ADFS authn - method is called, keystoneclient will login with the ADFS instance). - - :param fmt: Datetime format for specifying string format of a date. - It should not be changed if the method is going to be used - for building the ADFS security token request. - :type fmt: string - - """ - date_created = datetime.datetime.utcnow() - date_expires = date_created + datetime.timedelta( - seconds=self.DEFAULT_ADFS_TOKEN_EXPIRATION) - return [_time.strftime(fmt) for _time in (date_created, date_expires)] - - def _prepare_adfs_request(self): - """Build the ADFS Request Security Token SOAP message. - - Some values like username or password are inserted in the request. - - """ - WSS_SECURITY_NAMESPACE = { - 'o': ('http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-secext-1.0.xsd') - } - - TRUST_NAMESPACE = { - 'trust': 'http://docs.oasis-open.org/ws-sx/ws-trust/200512' - } - - WSP_NAMESPACE = { - 'wsp': 'http://schemas.xmlsoap.org/ws/2004/09/policy' - } - - WSA_NAMESPACE = { - 'wsa': 'http://www.w3.org/2005/08/addressing' - } - - root = etree.Element( - '{http://www.w3.org/2003/05/soap-envelope}Envelope', - nsmap=self.NAMESPACES) - - header = etree.SubElement( - root, '{http://www.w3.org/2003/05/soap-envelope}Header') - action = etree.SubElement( - header, "{http://www.w3.org/2005/08/addressing}Action") - action.set( - "{http://www.w3.org/2003/05/soap-envelope}mustUnderstand", "1") - action.text = ('http://docs.oasis-open.org/ws-sx/ws-trust/200512' - '/RST/Issue') - - messageID = etree.SubElement( - header, '{http://www.w3.org/2005/08/addressing}MessageID') - messageID.text = 'urn:uuid:' + uuid.uuid4().hex - replyID = etree.SubElement( - header, '{http://www.w3.org/2005/08/addressing}ReplyTo') - address = etree.SubElement( - replyID, '{http://www.w3.org/2005/08/addressing}Address') - address.text = 'http://www.w3.org/2005/08/addressing/anonymous' - - to = etree.SubElement( - header, '{http://www.w3.org/2005/08/addressing}To') - to.set("{http://www.w3.org/2003/05/soap-envelope}mustUnderstand", "1") - - security = etree.SubElement( - header, '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-secext-1.0.xsd}Security', - nsmap=WSS_SECURITY_NAMESPACE) - - security.set( - "{http://www.w3.org/2003/05/soap-envelope}mustUnderstand", "1") - - timestamp = etree.SubElement( - security, ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Timestamp')) - timestamp.set( - ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Id'), '_0') - - created = etree.SubElement( - timestamp, ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Created')) - - expires = etree.SubElement( - timestamp, ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-utility-1.0.xsd}Expires')) - - created.text, expires.text = self._token_dates() - - usernametoken = etree.SubElement( - security, '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-' - 'wss-wssecurity-secext-1.0.xsd}UsernameToken') - usernametoken.set( - ('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-' - 'wssecurity-utility-1.0.xsd}u'), "uuid-%s-1" % uuid.uuid4().hex) - - username = etree.SubElement( - usernametoken, ('{http://docs.oasis-open.org/wss/2004/01/oasis-' - '200401-wss-wssecurity-secext-1.0.xsd}Username')) - password = etree.SubElement( - usernametoken, ('{http://docs.oasis-open.org/wss/2004/01/oasis-' - '200401-wss-wssecurity-secext-1.0.xsd}Password'), - Type=('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-' - 'username-token-profile-1.0#PasswordText')) - - body = etree.SubElement( - root, "{http://www.w3.org/2003/05/soap-envelope}Body") - - request_security_token = etree.SubElement( - body, ('{http://docs.oasis-open.org/ws-sx/ws-trust/200512}' - 'RequestSecurityToken'), nsmap=TRUST_NAMESPACE) - - applies_to = etree.SubElement( - request_security_token, - '{http://schemas.xmlsoap.org/ws/2004/09/policy}AppliesTo', - nsmap=WSP_NAMESPACE) - - endpoint_reference = etree.SubElement( - applies_to, - '{http://www.w3.org/2005/08/addressing}EndpointReference', - nsmap=WSA_NAMESPACE) - - wsa_address = etree.SubElement( - endpoint_reference, - '{http://www.w3.org/2005/08/addressing}Address') - - keytype = etree.SubElement( - request_security_token, - '{http://docs.oasis-open.org/ws-sx/ws-trust/200512}KeyType') - keytype.text = ('http://docs.oasis-open.org/ws-sx/' - 'ws-trust/200512/Bearer') - - request_type = etree.SubElement( - request_security_token, - '{http://docs.oasis-open.org/ws-sx/ws-trust/200512}RequestType') - request_type.text = ('http://docs.oasis-open.org/ws-sx/' - 'ws-trust/200512/Issue') - token_type = etree.SubElement( - request_security_token, - '{http://docs.oasis-open.org/ws-sx/ws-trust/200512}TokenType') - token_type.text = 'urn:oasis:names:tc:SAML:1.0:assertion' - - # After constructing the request, let's plug in some values - username.text = self.username - password.text = self.password - to.text = self.identity_provider_url - wsa_address.text = self.service_provider_endpoint - - self.prepared_request = root - - def _get_adfs_security_token(self, session): - """Send ADFS Security token to the ADFS server. - - Store the result in the instance attribute and raise an exception in - case the response is not valid XML data. - - If a user cannot authenticate due to providing bad credentials, the - ADFS2.0 server will return a HTTP 500 response and a XML Fault message. - If ``exceptions.InternalServerError`` is caught, the method tries to - parse the XML response. - If parsing is unsuccessful, an ``exceptions.AuthorizationFailure`` is - raised with a reason from the XML fault. Otherwise an original - ``exceptions.InternalServerError`` is re-raised. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.AuthorizationFailure: when HTTP - response from the ADFS server is not a valid XML ADFS security - token. - :raises keystoneclient.exceptions.InternalServerError: If response - status code is HTTP 500 and the response XML cannot be - recognized. - - """ - def _get_failure(e): - xpath = '/s:Envelope/s:Body/s:Fault/s:Code/s:Subcode/s:Value' - content = e.response.content - try: - obj = self.str_to_xml(content).xpath( - xpath, namespaces=self.NAMESPACES) - obj = self._first(obj) - return obj.text - # NOTE(marek-denis): etree.Element.xpath() doesn't raise an - # exception, it just returns an empty list. In that case, _first() - # will raise IndexError and we should treat it as an indication XML - # is not valid. exceptions.AuthorizationFailure can be raised from - # str_to_xml(), however since server returned HTTP 500 we should - # re-raise exceptions.InternalServerError. - except (IndexError, exceptions.AuthorizationFailure): - raise e - - request_security_token = self.xml_to_str(self.prepared_request) - try: - response = session.post( - url=self.identity_provider_url, headers=self.HEADER_SOAP, - data=request_security_token, authenticated=False) - except exceptions.InternalServerError as e: - reason = _get_failure(e) - raise exceptions.AuthorizationFailure(reason) - msg = _("Error parsing XML returned from " - "the ADFS Identity Provider, reason: %s") - self.adfs_token = self.str_to_xml(response.content, msg) - - def _prepare_sp_request(self): - """Prepare ADFS Security Token to be sent to the Service Provider. - - The method works as follows: - * Extract SAML2 assertion from the ADFS Security Token. - * Replace namespaces - * urlencode assertion - * concatenate static string with the encoded assertion - - """ - assertion = self.adfs_token.xpath( - self.ADFS_ASSERTION_XPATH, namespaces=self.ADFS_TOKEN_NAMESPACES) - assertion = self._first(assertion) - assertion = self.xml_to_str(assertion) - # TODO(marek-denis): Ideally no string replacement should occur. - # Unfortunately lxml doesn't allow for namespaces changing in-place and - # probably the only solution good for now is to build the assertion - # from scratch and reuse values from the adfs security token. - assertion = assertion.replace( - b'http://docs.oasis-open.org/ws-sx/ws-trust/200512', - b'http://schemas.xmlsoap.org/ws/2005/02/trust') - - encoded_assertion = urllib.parse.quote(assertion) - self.encoded_assertion = 'wa=wsignin1.0&wresult=' + encoded_assertion - - def _send_assertion_to_service_provider(self, session): - """Send prepared assertion to a service provider. - - As the assertion doesn't contain a protected resource, the value from - the ``location`` header is not valid and we should not let the Session - object get redirected there. The aim of this call is to get a cookie in - the response which is required for entering a protected endpoint. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :raises: Corresponding HTTP error exception - - """ - session.post( - url=self.service_provider_endpoint, data=self.encoded_assertion, - headers=self.HEADER_X_FORM, redirect=False, authenticated=False) - - def _access_service_provider(self, session): - """Access protected endpoint and fetch unscoped token. - - After federated authentication workflow a protected endpoint should be - accessible with the session object. The access is granted basing on the - cookies stored within the session object. If, for some reason no - cookies are present (quantity test) it means something went wrong and - user will not be able to fetch an unscoped token. In that case an - ``exceptions.AuthorizationFailure` exception is raised and no HTTP call - is even made. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :raises keystoneclient.exceptions.AuthorizationFailure: in case session - object has empty cookie jar. - - """ - if self._cookies(session) is False: - raise exceptions.AuthorizationFailure( - _("Session object doesn't contain a cookie, therefore you are " - "not allowed to enter the Identity Provider's protected " - "area.")) - self.authenticated_response = session.get(self.token_url, - authenticated=False) - - def _get_unscoped_token(self, session, *kwargs): - """Retrieve unscoped token after authentcation with ADFS server. - - This is a multistep process:: - - * Prepare ADFS Request Securty Token - - build an etree.XML object filling certain attributes with proper user - credentials, created/expires dates (ticket is be valid for 120 seconds - as currently we don't handle reusing ADFS issued security tokens) . - Step handled by ``ADFSUnscopedToken._prepare_adfs_request()`` method. - - * Send ADFS Security token to the ADFS server. Step handled by - ``ADFSUnscopedToken._get_adfs_security_token()`` method. - - * Receive and parse security token, extract actual SAML assertion and - prepare a request addressed for the Service Provider endpoint. - This also includes changing namespaces in the XML document. Step - handled by ``ADFSUnscopedToken._prepare_sp_request()`` method. - - * Send prepared assertion to the Service Provider endpoint. Usually - the server will respond with HTTP 301 code which should be ignored as - the 'location' header doesn't contain protected area. The goal of this - operation is fetching the session cookie which later allows for - accessing protected URL endpoints. Step handed by - ``ADFSUnscopedToken._send_assertion_to_service_provider()`` method. - - * Once the session cookie is issued, the protected endpoint can be - accessed and an unscoped token can be retrieved. Step handled by - ``ADFSUnscopedToken._access_service_provider()`` method. - - :param session : a session object to send out HTTP requests. - :type session: keystoneclient.session.Session - - :returns: (Unscoped federated token, token JSON body) - - """ - self._prepare_adfs_request() - self._get_adfs_security_token(session) - self._prepare_sp_request() - self._send_assertion_to_service_provider(session) - self._access_service_provider(session) - - try: - return (self.authenticated_response.headers['X-Subject-Token'], - self.authenticated_response.json()['token']) - except (KeyError, ValueError): - raise exceptions.InvalidResponse( - response=self.authenticated_response) - - def get_auth_ref(self, session, **kwargs): - token, token_json = self._get_unscoped_token(session) - return access.AccessInfoV3(token, **token_json) - - -class Saml2ScopedTokenMethod(v3.TokenMethod): - _method_name = 'saml2' - - def get_auth_data(self, session, auth, headers, **kwargs): - """Build and return request body for token scoping step.""" - t = super(Saml2ScopedTokenMethod, self).get_auth_data( - session, auth, headers, **kwargs) - _token_method, token = t - return self._method_name, token - - -class Saml2ScopedToken(v3.Token): - """Class for scoping unscoped saml2 token.""" - - _auth_method_class = Saml2ScopedTokenMethod - - def __init__(self, auth_url, token, **kwargs): - super(Saml2ScopedToken, self).__init__(auth_url, token, **kwargs) - if not (self.project_id or self.domain_id): - raise exceptions.ValidationError( - _('Neither project nor domain specified')) diff --git a/keystoneclient/contrib/ec2/__init__.py b/keystoneclient/contrib/ec2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/contrib/ec2/utils.py b/keystoneclient/contrib/ec2/utils.py deleted file mode 100644 index 1ef5df4d..00000000 --- a/keystoneclient/contrib/ec2/utils.py +++ /dev/null @@ -1,287 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2011 - 2012 Justin Santa Barbara -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import base64 -import hashlib -import hmac -import re - -import six -from six.moves import urllib - -from keystoneclient.i18n import _ - - -class Ec2Signer(object): - """Utility class for EC2 signing of request. - - This allows a request to be signed with an AWS style signature, - which can then be used for authentication via the keystone ec2 - authentication extension. - """ - - def __init__(self, secret_key): - self.secret_key = secret_key.encode() - self.hmac = hmac.new(self.secret_key, digestmod=hashlib.sha1) - if hashlib.sha256: - self.hmac_256 = hmac.new(self.secret_key, digestmod=hashlib.sha256) - - def _v4_creds(self, credentials): - """Detect if the credentials are for a v4 signed request. - - Check is needed since AWS removed the SignatureVersion field from - the v4 request spec... - - This expects a dict of the request headers to be passed in the - credentials dict, since the recommended way to pass v4 creds is - via the 'Authorization' header - see http://docs.aws.amazon.com/general/latest/gr/ - sigv4-signed-request-examples.html - - Alternatively X-Amz-Algorithm can be specified as a query parameter, - and the authentication data can also passed as query parameters. - - Note a hash of the request body is also required in the credentials - for v4 auth to work in the body_hash key, calculated via: - hashlib.sha256(req.body).hexdigest() - """ - try: - auth_str = credentials['headers']['Authorization'] - if auth_str.startswith('AWS4-HMAC-SHA256'): - return True - except KeyError: - # Alternatively the Authorization data can be passed via - # the query params list, check X-Amz-Algorithm=AWS4-HMAC-SHA256 - try: - if (credentials['params']['X-Amz-Algorithm'] == - 'AWS4-HMAC-SHA256'): - return True - except KeyError: # nosec(cjschaef): in cases of not finding - # entries, simply return False - pass - - return False - - def generate(self, credentials): - """Generate auth string according to what SignatureVersion is given.""" - signature_version = credentials['params'].get('SignatureVersion') - if signature_version == '0': - return self._calc_signature_0(credentials['params']) - if signature_version == '1': - return self._calc_signature_1(credentials['params']) - if signature_version == '2': - return self._calc_signature_2(credentials['params'], - credentials['verb'], - credentials['host'], - credentials['path']) - if self._v4_creds(credentials): - return self._calc_signature_4(credentials['params'], - credentials['verb'], - credentials['host'], - credentials['path'], - credentials['headers'], - credentials['body_hash']) - - if signature_version is not None: - raise Exception(_('Unknown signature version: %s') % - signature_version) - else: - raise Exception(_('Unexpected signature format')) - - @staticmethod - def _get_utf8_value(value): - """Get the UTF8-encoded version of a value.""" - if not isinstance(value, (six.binary_type, six.text_type)): - value = str(value) - if isinstance(value, six.text_type): - return value.encode('utf-8') - else: - return value - - def _calc_signature_0(self, params): - """Generate AWS signature version 0 string.""" - s = (params['Action'] + params['Timestamp']).encode('utf-8') - self.hmac.update(s) - return base64.b64encode(self.hmac.digest()).decode('utf-8') - - def _calc_signature_1(self, params): - """Generate AWS signature version 1 string.""" - keys = list(params) - keys.sort(key=six.text_type.lower) - for key in keys: - self.hmac.update(key.encode('utf-8')) - val = self._get_utf8_value(params[key]) - self.hmac.update(val) - return base64.b64encode(self.hmac.digest()).decode('utf-8') - - @staticmethod - def _canonical_qs(params): - """Construct a sorted, correctly encoded query string. - - This is required for _calc_signature_2 and _calc_signature_4. - """ - keys = list(params) - keys.sort() - pairs = [] - for key in keys: - val = Ec2Signer._get_utf8_value(params[key]) - val = urllib.parse.quote(val, safe='-_~') - pairs.append(urllib.parse.quote(key, safe='') + '=' + val) - qs = '&'.join(pairs) - return qs - - def _calc_signature_2(self, params, verb, server_string, path): - """Generate AWS signature version 2 string.""" - string_to_sign = '%s\n%s\n%s\n' % (verb, server_string, path) - if self.hmac_256: - current_hmac = self.hmac_256 - params['SignatureMethod'] = 'HmacSHA256' - else: - current_hmac = self.hmac - params['SignatureMethod'] = 'HmacSHA1' - string_to_sign += self._canonical_qs(params) - current_hmac.update(string_to_sign.encode('utf-8')) - b64 = base64.b64encode(current_hmac.digest()).decode('utf-8') - return b64 - - def _calc_signature_4(self, params, verb, server_string, path, headers, - body_hash): - """Generate AWS signature version 4 string.""" - def sign(key, msg): - return hmac.new(key, self._get_utf8_value(msg), - hashlib.sha256).digest() - - def signature_key(datestamp, region_name, service_name): - """Signature key derivation. - - See http://docs.aws.amazon.com/general/latest/gr/ - signature-v4-examples.html#signature-v4-examples-python - """ - k_date = sign(self._get_utf8_value(b"AWS4" + self.secret_key), - datestamp) - k_region = sign(k_date, region_name) - k_service = sign(k_region, service_name) - k_signing = sign(k_service, "aws4_request") - return k_signing - - def auth_param(param_name): - """Get specified auth parameter. - - Provided via one of: - - the Authorization header - - the X-Amz-* query parameters - """ - try: - auth_str = headers['Authorization'] - param_str = auth_str.partition( - '%s=' % param_name)[2].split(',')[0] - except KeyError: - param_str = params.get('X-Amz-%s' % param_name) - return param_str - - def date_param(): - """Get the X-Amz-Date' value. - - The value can be either a header or parameter. - - Note AWS supports parsing the Date header also, but this is not - currently supported here as it will require some format mangling - So the X-Amz-Date value must be YYYYMMDDTHHMMSSZ format, then it - can be used to match against the YYYYMMDD format provided in the - credential scope. - see: - http://docs.aws.amazon.com/general/latest/gr/ - sigv4-date-handling.html - """ - try: - return headers['X-Amz-Date'] - except KeyError: - return params.get('X-Amz-Date') - - def canonical_header_str(): - # Get the list of headers to include, from either - # - the Authorization header (SignedHeaders key) - # - the X-Amz-SignedHeaders query parameter - headers_lower = dict((k.lower().strip(), v.strip()) - for (k, v) in headers.items()) - - # Boto versions < 2.9.3 strip the port component of the host:port - # header, so detect the user-agent via the header and strip the - # port if we detect an old boto version. FIXME: remove when all - # distros package boto >= 2.9.3, this is a transitional workaround - user_agent = headers_lower.get('user-agent', '') - strip_port = re.match('Boto/2\.[0-9]\.[0-2]', user_agent) - - header_list = [] - sh_str = auth_param('SignedHeaders') - for h in sh_str.split(';'): - if h not in headers_lower: - continue - - if h == 'host' and strip_port: - header_list.append('%s:%s' % - (h, headers_lower[h].split(':')[0])) - continue - - header_list.append('%s:%s' % (h, headers_lower[h])) - return '\n'.join(header_list) + '\n' - - def canonical_query_str(verb, params): - # POST requests pass parameters in through the request body - canonical_qs = '' - if verb.upper() != 'POST': - canonical_qs = self._canonical_qs(params) - return canonical_qs - - # Create canonical request: - # http://docs.aws.amazon.com/general/latest/gr/ - # sigv4-create-canonical-request.html - # Get parameters and headers in expected string format - cr = "\n".join((verb.upper(), path, - canonical_query_str(verb, params), - canonical_header_str(), - auth_param('SignedHeaders'), - body_hash)) - - # Check the date, reject any request where the X-Amz-Date doesn't - # match the credential scope - credential = auth_param('Credential') - credential_split = credential.split('/') - credential_scope = '/'.join(credential_split[1:]) - credential_date = credential_split[1] - param_date = date_param() - if not param_date.startswith(credential_date): - raise Exception(_('Request date mismatch error')) - - # Create the string to sign - # http://docs.aws.amazon.com/general/latest/gr/ - # sigv4-create-string-to-sign.html - cr = cr.encode('utf-8') - string_to_sign = '\n'.join(('AWS4-HMAC-SHA256', - param_date, - credential_scope, - hashlib.sha256(cr).hexdigest())) - - # Calculate the derived key, this requires a datestamp, region - # and service, which can be extracted from the credential scope - (req_region, req_service) = credential_split[2:4] - s_key = signature_key(credential_date, req_region, req_service) - # Finally calculate the signature! - signature = hmac.new(s_key, self._get_utf8_value(string_to_sign), - hashlib.sha256).hexdigest() - return signature diff --git a/keystoneclient/discover.py b/keystoneclient/discover.py deleted file mode 100644 index 823c94cd..00000000 --- a/keystoneclient/discover.py +++ /dev/null @@ -1,364 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import warnings - -from debtcollector import removals -from keystoneauth1 import plugin -from positional import positional - -from keystoneclient import _discover -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import session as client_session -from keystoneclient.v2_0 import client as v2_client -from keystoneclient.v3 import client as v3_client - - -_CLIENT_VERSIONS = {2: v2_client.Client, - 3: v3_client.Client} - - -# functions needed from the private file that can be made public - -def normalize_version_number(version): - """Turn a version representation into a tuple. - - Takes a string, tuple or float which represent version formats we can - handle and converts them into a (major, minor) version tuple that we can - actually use for discovery. - - e.g. 'v3.3' gives (3, 3) - 3.1 gives (3, 1) - - :param version: Inputted version number to try and convert. - - :returns: A usable version tuple - :rtype: tuple - - :raises TypeError: if the inputted version cannot be converted to tuple. - """ - return _discover.normalize_version_number(version) - - -def version_match(required, candidate): - """Test that an available version satisfies the required version. - - To be suitable a version must be of the same major version as required - and be at least a match in minor/patch level. - - eg. 3.3 is a match for a required 3.1 but 4.1 is not. - - :param tuple required: the version that must be met. - :param tuple candidate: the version to test against required. - - :returns: True if candidate is suitable False otherwise. - :rtype: bool - """ - return _discover.version_match(required, candidate) - - -def available_versions(url, session=None, **kwargs): - """Retrieve raw version data from a url.""" - if not session: - session = client_session.Session._construct(kwargs) - - return _discover.get_version_data(session, url) - - -class Discover(_discover.Discover): - """A means to discover and create clients. - - Clients are created depending on the supported API versions on the server. - - Querying the server is done on object creation and every subsequent method - operates upon the data that was retrieved. - - The connection parameters associated with this method are the same format - and name as those used by a client (see - :py:class:`keystoneclient.v2_0.client.Client` and - :py:class:`keystoneclient.v3.client.Client`). If not overridden in - subsequent methods they will also be what is passed to the constructed - client. - - In the event that auth_url and endpoint is provided then auth_url will be - used in accordance with how the client operates. - - .. warning:: - - Creating an instance of this class without using the session argument - is deprecated as of the 1.7.0 release and may be removed in the 2.0.0 - release. - - :param session: A session object that will be used for communication. - Clients will also be constructed with this session. - :type session: keystoneclient.session.Session - :param string auth_url: Identity service endpoint for authorization. - (optional) - :param string endpoint: A user-supplied endpoint URL for the identity - service. (optional) - :param string original_ip: The original IP of the requesting user which - will be sent to identity service in a - 'Forwarded' header. (optional) This is ignored - if a session is provided. Deprecated as of the - 1.7.0 release and may be removed in the 2.0.0 - release. - :param boolean debug: Enables debug logging of all request and responses to - the identity service. default False (optional) - This is ignored if a session is provided. Deprecated - as of the 1.7.0 release and may be removed in the - 2.0.0 release. - :param string cacert: Path to the Privacy Enhanced Mail (PEM) file which - contains the trusted authority X.509 certificates - needed to established SSL connection with the - identity service. (optional) This is ignored if a - session is provided. Deprecated as of the 1.7.0 - release and may be removed in the 2.0.0 release. - :param string key: Path to the Privacy Enhanced Mail (PEM) file which - contains the unencrypted client private key needed to - established two-way SSL connection with the identity - service. (optional) This is ignored if a session is - provided. Deprecated as of the 1.7.0 release and may be - removed in the 2.0.0 release. - :param string cert: Path to the Privacy Enhanced Mail (PEM) file which - contains the corresponding X.509 client certificate - needed to established two-way SSL connection with the - identity service. (optional) This is ignored if a - session is provided. Deprecated as of the 1.7.0 release - and may be removed in the 2.0.0 release. - :param boolean insecure: Does not perform X.509 certificate validation when - establishing SSL connection with identity service. - default: False (optional) This is ignored if a - session is provided. Deprecated as of the 1.7.0 - release and may be removed in the 2.0.0 release. - :param bool authenticated: Should a token be used to perform the initial - discovery operations. default: None (attach a - token if an auth plugin is available). - - """ - - @positional(2) - def __init__(self, session=None, authenticated=None, **kwargs): - if not session: - warnings.warn( - 'Constructing a Discover instance without using a session is ' - 'deprecated as of the 1.7.0 release and may be removed in the ' - '2.0.0 release.', DeprecationWarning) - session = client_session.Session._construct(kwargs) - kwargs['session'] = session - - url = None - endpoint = kwargs.pop('endpoint', None) - auth_url = kwargs.pop('auth_url', None) - - if endpoint: - self._use_endpoint = True - url = endpoint - elif auth_url: - self._use_endpoint = False - url = auth_url - elif session.auth: - self._use_endpoint = False - url = session.get_endpoint(interface=plugin.AUTH_INTERFACE) - - if not url: - raise exceptions.DiscoveryFailure( - _('Not enough information to determine URL. Provide' - ' either a Session, or auth_url or endpoint')) - - self._client_kwargs = kwargs - super(Discover, self).__init__(session, url, - authenticated=authenticated) - - @removals.remove(message='Use raw_version_data instead.', version='1.7.0', - removal_version='2.0.0') - def available_versions(self, **kwargs): - """Return a list of identity APIs available on the server. - - The list returned includes the data associated with them. - - .. warning:: - - This method is deprecated as of the 1.7.0 release in favor of - :meth:`raw_version_data` and may be removed in the 2.0.0 release. - - :param bool unstable: Accept endpoints not marked 'stable'. (optional) - Equates to setting allow_experimental - and allow_unknown to True. - :param bool allow_experimental: Allow experimental version endpoints. - :param bool allow_deprecated: Allow deprecated version endpoints. - :param bool allow_unknown: Allow endpoints with an unrecognised status. - - :returns: A List of dictionaries as presented by the server. Each dict - will contain the version and the URL to use for the version. - It is a direct representation of the layout presented by the - identity API. - """ - return self.raw_version_data(**kwargs) - - @removals.removed_kwarg( - 'unstable', - message='Use allow_experimental and allow_unknown instead.', - version='1.7.0', removal_version='2.0.0') - def raw_version_data(self, unstable=False, **kwargs): - """Get raw version information from URL. - - Raw data indicates that only minimal validation processing is performed - on the data, so what is returned here will be the data in the same - format it was received from the endpoint. - - :param bool unstable: equates to setting allow_experimental and - allow_unknown. This argument is deprecated as of - the 1.7.0 release and may be removed in the 2.0.0 - release. - :param bool allow_experimental: Allow experimental version endpoints. - :param bool allow_deprecated: Allow deprecated version endpoints. - :param bool allow_unknown: Allow endpoints with an unrecognised status. - - :returns: The endpoints returned from the server that match the - criteria. - :rtype: List - - Example:: - - >>> from keystoneclient import discover - >>> disc = discover.Discovery(auth_url='http://localhost:5000') - >>> disc.raw_version_data() - [{'id': 'v3.0', - 'links': [{'href': u'http://127.0.0.1:5000/v3/', - 'rel': u'self'}], - 'media-types': [ - {'base': 'application/json', - 'type': 'application/vnd.openstack.identity-v3+json'}, - {'base': 'application/xml', - 'type': 'application/vnd.openstack.identity-v3+xml'}], - 'status': 'stable', - 'updated': '2013-03-06T00:00:00Z'}, - {'id': 'v2.0', - 'links': [{'href': u'http://127.0.0.1:5000/v2.0/', - 'rel': u'self'}, - {'href': u'...', - 'rel': u'describedby', - 'type': u'application/pdf'}], - 'media-types': [ - {'base': 'application/json', - 'type': 'application/vnd.openstack.identity-v2.0+json'}, - {'base': 'application/xml', - 'type': 'application/vnd.openstack.identity-v2.0+xml'}], - 'status': 'stable', - 'updated': '2013-03-06T00:00:00Z'}] - """ - if unstable: - kwargs.setdefault('allow_experimental', True) - kwargs.setdefault('allow_unknown', True) - - return super(Discover, self).raw_version_data(**kwargs) - - def _calculate_version(self, version, unstable): - version_data = None - - if version: - version_data = self.data_for(version) - else: - # if no version specified pick the latest one - all_versions = self.version_data(unstable=unstable) - if all_versions: - version_data = all_versions[-1] - - if not version_data: - msg = _('Could not find a suitable endpoint') - - if version: - msg = _('Could not find a suitable endpoint for client ' - 'version: %s') % str(version) - - raise exceptions.VersionNotAvailable(msg) - - return version_data - - def _create_client(self, version_data, **kwargs): - # Get the client for the version requested that was returned - try: - client_class = _CLIENT_VERSIONS[version_data['version'][0]] - except KeyError: - version = '.'.join(str(v) for v in version_data['version']) - msg = _('No client available for version: %s') % version - raise exceptions.DiscoveryFailure(msg) - - # kwargs should take priority over stored kwargs. - for k, v in self._client_kwargs.items(): - kwargs.setdefault(k, v) - - # restore the url to either auth_url or endpoint depending on what - # was initially given - if self._use_endpoint: - kwargs['auth_url'] = None - kwargs['endpoint'] = version_data['url'] - else: - kwargs['auth_url'] = version_data['url'] - kwargs['endpoint'] = None - - return client_class(**kwargs) - - def create_client(self, version=None, unstable=False, **kwargs): - """Factory function to create a new identity service client. - - :param tuple version: The required version of the identity API. If - specified the client will be selected such that - the major version is equivalent and an endpoint - provides at least the specified minor version. - For example to specify the 3.1 API use (3, 1). - (optional) - :param bool unstable: Accept endpoints not marked 'stable'. (optional) - :param kwargs: Additional arguments will override those provided to - this object's constructor. - - :returns: An instantiated identity client object. - - :raises keystoneclient.exceptions.DiscoveryFailure: if the server - response is invalid - :raises keystoneclient.exceptions.VersionNotAvailable: if a suitable - client cannot be found. - """ - version_data = self._calculate_version(version, unstable) - return self._create_client(version_data, **kwargs) - - -def add_catalog_discover_hack(service_type, old, new): - """Add a version removal rule for a particular service. - - Originally deployments of OpenStack would contain a versioned endpoint in - the catalog for different services. E.g. an identity service might look - like ``http://localhost:5000/v2.0``. This is a problem when we want to use - a different version like v3.0 as there is no way to tell where it is - located. We cannot simply change all service catalogs either so there must - be a way to handle the older style of catalog. - - This function adds a rule for a given service type that if part of the URL - matches a given regular expression in *old* then it will be replaced with - the *new* value. This will replace all instances of old with new. It should - therefore contain a regex anchor. - - For example the included rule states:: - - add_catalog_version_hack('identity', re.compile('/v2.0/?$'), '/') - - so if the catalog retrieves an *identity* URL that ends with /v2.0 or - /v2.0/ then it should replace it simply with / to fix the user's catalog. - - :param str service_type: The service type as defined in the catalog that - the rule will apply to. - :param re.RegexObject old: The regular expression to search for and replace - if found. - :param str new: The new string to replace the pattern with. - """ - _discover._VERSION_HACKS.add_discover_hack(service_type, old, new) diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py deleted file mode 100644 index 5b06be9b..00000000 --- a/keystoneclient/exceptions.py +++ /dev/null @@ -1,437 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 Nebula, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Exception definitions.""" - -from keystoneauth1 import exceptions as _exc - -from keystoneclient.i18n import _ - - -ClientException = _exc.ClientException -"""The base exception class for all exceptions this library raises. - -An alias of :py:exc:`keystoneauth1.exceptions.base.ClientException` -""" - -ConnectionError = _exc.ConnectionError -"""Cannot connect to API service. - -An alias of :py:exc:`keystoneauth1.exceptions.connection.ConnectionError` -""" - -ConnectionRefused = _exc.ConnectFailure -"""Connection refused while trying to connect to API service. - -An alias of :py:exc:`keystoneauth1.exceptions.connection.ConnectFailure` -""" - -SSLError = _exc.SSLError -"""An SSL error occurred. - -An alias of :py:exc:`keystoneauth1.exceptions.connection.SSLError` -""" - -AuthorizationFailure = _exc.AuthorizationFailure -"""Cannot authorize API client. - -An alias of :py:exc:`keystoneauth1.exceptions.auth.AuthorizationFailure` -""" - - -class ValidationError(ClientException): - """Error in validation on API client side.""" - - pass - - -class UnsupportedVersion(ClientException): - """User is trying to use an unsupported version of the API.""" - - pass - - -class CommandError(ClientException): - """Error in CLI tool.""" - - pass - - -class AuthPluginOptionsMissing(AuthorizationFailure): - """Auth plugin misses some options.""" - - def __init__(self, opt_names): - super(AuthPluginOptionsMissing, self).__init__( - _("Authentication failed. Missing options: %s") % - ", ".join(opt_names)) - self.opt_names = opt_names - - -class AuthSystemNotFound(AuthorizationFailure): - """User has specified an AuthSystem that is not installed.""" - - def __init__(self, auth_system): - super(AuthSystemNotFound, self).__init__( - _("AuthSystemNotFound: %r") % auth_system) - self.auth_system = auth_system - - -class NoUniqueMatch(ClientException): - """Multiple entities found instead of one.""" - - pass - - -EndpointException = _exc.CatalogException -"""Something is rotten in Service Catalog. - -An alias of :py:exc:`keystoneauth1.exceptions.catalog.CatalogException` -""" - -EndpointNotFound = _exc.EndpointNotFound -"""Could not find requested endpoint in Service Catalog. - -An alias of :py:exc:`keystoneauth1.exceptions.catalog.EndpointNotFound` -""" - - -class AmbiguousEndpoints(EndpointException): - """Found more than one matching endpoint in Service Catalog.""" - - def __init__(self, endpoints=None): - super(AmbiguousEndpoints, self).__init__( - _("AmbiguousEndpoints: %r") % endpoints) - self.endpoints = endpoints - - -HttpError = _exc.HttpError -"""The base exception class for all HTTP exceptions. - -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpError` -""" - -HTTPClientError = _exc.HTTPClientError -"""Client-side HTTP error. - -Exception for cases in which the client seems to have erred. -An alias of :py:exc:`keystoneauth1.exceptions.http.HTTPClientError` -""" - -HttpServerError = _exc.HttpServerError -"""Server-side HTTP error. - -Exception for cases in which the server is aware that it has -erred or is incapable of performing the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpServerError` -""" - - -class HTTPRedirection(HttpError): - """HTTP Redirection.""" - - message = _("HTTP Redirection") - - -class MultipleChoices(HTTPRedirection): - """HTTP 300 - Multiple Choices. - - Indicates multiple options for the resource that the client may follow. - """ - - http_status = 300 - message = _("Multiple Choices") - - -BadRequest = _exc.BadRequest -"""HTTP 400 - Bad Request. - -The request cannot be fulfilled due to bad syntax. -An alias of :py:exc:`keystoneauth1.exceptions.http.BadRequest` -""" - -Unauthorized = _exc.Unauthorized -"""HTTP 401 - Unauthorized. - -Similar to 403 Forbidden, but specifically for use when authentication -is required and has failed or has not yet been provided. -An alias of :py:exc:`keystoneauth1.exceptions.http.Unauthorized` -""" - -PaymentRequired = _exc.PaymentRequired -"""HTTP 402 - Payment Required. - -Reserved for future use. -An alias of :py:exc:`keystoneauth1.exceptions.http.PaymentRequired` -""" - -Forbidden = _exc.Forbidden -"""HTTP 403 - Forbidden. - -The request was a valid request, but the server is refusing to respond -to it. -An alias of :py:exc:`keystoneauth1.exceptions.http.Forbidden` -""" - -NotFound = _exc.NotFound -"""HTTP 404 - Not Found. - -The requested resource could not be found but may be available again -in the future. -An alias of :py:exc:`keystoneauth1.exceptions.http.NotFound` -""" - -MethodNotAllowed = _exc.MethodNotAllowed -"""HTTP 405 - Method Not Allowed. - -A request was made of a resource using a request method not supported -by that resource. -An alias of :py:exc:`keystoneauth1.exceptions.http.MethodNotAllowed` -""" - -NotAcceptable = _exc.NotAcceptable -"""HTTP 406 - Not Acceptable. - -The requested resource is only capable of generating content not -acceptable according to the Accept headers sent in the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.NotAcceptable` -""" - -ProxyAuthenticationRequired = _exc.ProxyAuthenticationRequired -"""HTTP 407 - Proxy Authentication Required. - -The client must first authenticate itself with the proxy. -An alias of :py:exc:`keystoneauth1.exceptions.http.ProxyAuthenticationRequired` -""" - -RequestTimeout = _exc.RequestTimeout -"""HTTP 408 - Request Timeout. - -The server timed out waiting for the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.RequestTimeout` -""" - -Conflict = _exc.Conflict -"""HTTP 409 - Conflict. - -Indicates that the request could not be processed because of conflict -in the request, such as an edit conflict. -An alias of :py:exc:`keystoneauth1.exceptions.http.Conflict` -""" - -Gone = _exc.Gone -"""HTTP 410 - Gone. - -Indicates that the resource requested is no longer available and will -not be available again. -An alias of :py:exc:`keystoneauth1.exceptions.http.Gone` -""" - -LengthRequired = _exc.LengthRequired -"""HTTP 411 - Length Required. - -The request did not specify the length of its content, which is -required by the requested resource. -An alias of :py:exc:`keystoneauth1.exceptions.http.LengthRequired` -""" - -PreconditionFailed = _exc.PreconditionFailed -"""HTTP 412 - Precondition Failed. - -The server does not meet one of the preconditions that the requester -put on the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.PreconditionFailed` -""" - -RequestEntityTooLarge = _exc.RequestEntityTooLarge -"""HTTP 413 - Request Entity Too Large. - -The request is larger than the server is willing or able to process. -An alias of :py:exc:`keystoneauth1.exceptions.http.RequestEntityTooLarge` -""" - -RequestUriTooLong = _exc.RequestUriTooLong -"""HTTP 414 - Request-URI Too Long. - -The URI provided was too long for the server to process. -An alias of :py:exc:`keystoneauth1.exceptions.http.RequestUriTooLong` -""" - -UnsupportedMediaType = _exc.UnsupportedMediaType -"""HTTP 415 - Unsupported Media Type. - -The request entity has a media type which the server or resource does -not support. -An alias of :py:exc:`keystoneauth1.exceptions.http.UnsupportedMediaType` -""" - -RequestedRangeNotSatisfiable = _exc.RequestedRangeNotSatisfiable -"""HTTP 416 - Requested Range Not Satisfiable. - -The client has asked for a portion of the file, but the server cannot -supply that portion. -An alias of -:py:exc:`keystoneauth1.exceptions.http.RequestedRangeNotSatisfiable` -""" - -ExpectationFailed = _exc.ExpectationFailed -"""HTTP 417 - Expectation Failed. - -The server cannot meet the requirements of the Expect request-header field. -An alias of :py:exc:`keystoneauth1.exceptions.http.ExpectationFailed` -""" - -UnprocessableEntity = _exc.UnprocessableEntity -"""HTTP 422 - Unprocessable Entity. - -The request was well-formed but was unable to be followed due to semantic -errors. -An alias of :py:exc:`keystoneauth1.exceptions.http.UnprocessableEntity` -""" - -InternalServerError = _exc.InternalServerError -"""HTTP 500 - Internal Server Error. - -A generic error message, given when no more specific message is suitable. -An alias of :py:exc:`keystoneauth1.exceptions.http.InternalServerError` -""" - -HttpNotImplemented = _exc.HttpNotImplemented -"""HTTP 501 - Not Implemented. - -The server either does not recognize the request method, or it lacks -the ability to fulfill the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpNotImplemented` -""" - -BadGateway = _exc.BadGateway -"""HTTP 502 - Bad Gateway. - -The server was acting as a gateway or proxy and received an invalid -response from the upstream server. -An alias of :py:exc:`keystoneauth1.exceptions.http.BadGateway` -""" - -ServiceUnavailable = _exc.ServiceUnavailable -"""HTTP 503 - Service Unavailable. - -The server is currently unavailable. -An alias of :py:exc:`keystoneauth1.exceptions.http.ServiceUnavailable` -""" - -GatewayTimeout = _exc.GatewayTimeout -"""HTTP 504 - Gateway Timeout. - -The server was acting as a gateway or proxy and did not receive a timely -response from the upstream server. -An alias of :py:exc:`keystoneauth1.exceptions.http.GatewayTimeout` -""" - -HttpVersionNotSupported = _exc.HttpVersionNotSupported -"""HTTP 505 - HttpVersion Not Supported. - -The server does not support the HTTP protocol version used in the request. -An alias of :py:exc:`keystoneauth1.exceptions.http.HttpVersionNotSupported` -""" - -from_response = _exc.from_response -"""Return an instance of :class:`HttpError` or subclass based on response. - -An alias of :py:func:`keystoneauth1.exceptions.http.from_response` -""" - - -# NOTE(akurilin): This alias should be left here to support backwards -# compatibility until we are sure that usage of these exceptions in -# projects is correct. -HTTPNotImplemented = HttpNotImplemented -Timeout = RequestTimeout -HTTPError = HttpError - - -class CertificateConfigError(Exception): - """Error reading the certificate.""" - - def __init__(self, output): - self.output = output - msg = _('Unable to load certificate.') - super(CertificateConfigError, self).__init__(msg) - - -class CMSError(Exception): - """Error reading the certificate.""" - - def __init__(self, output): - self.output = output - msg = _('Unable to sign or verify data.') - super(CMSError, self).__init__(msg) - -EmptyCatalog = _exc.EmptyCatalog -"""The service catalog is empty. - -An alias of :py:exc:`keystoneauth1.exceptions.catalog.EmptyCatalog` -""" - -DiscoveryFailure = _exc.DiscoveryFailure -"""Discovery of client versions failed. - -An alias of :py:exc:`keystoneauth1.exceptions.discovery.DiscoveryFailure` -""" - -VersionNotAvailable = _exc.VersionNotAvailable -"""Discovery failed as the version you requested is not available. - -An alias of :py:exc:`keystoneauth1.exceptions.discovery.VersionNotAvailable` -""" - - -class MethodNotImplemented(ClientException): - """Method not implemented by the keystoneclient API.""" - -MissingAuthPlugin = _exc.MissingAuthPlugin -"""An authenticated request is required but no plugin available. - -An alias of :py:exc:`keystoneauth1.exceptions.auth_plugins.MissingAuthPlugin` -""" - -NoMatchingPlugin = _exc.NoMatchingPlugin -"""There were no auth plugins that could be created from the parameters -provided. - -An alias of :py:exc:`keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin` -""" - - -class UnsupportedParameters(ClientException): - """A parameter that was provided or returned is not supported. - - :param List(str) names: Names of the unsupported parameters. - - .. py:attribute:: names - - Names of the unsupported parameters. - """ - - def __init__(self, names): - self.names = names - - m = _('The following parameters were given that are unsupported: %s') - super(UnsupportedParameters, self).__init__(m % ', '.join(self.names)) - - -class InvalidResponse(ClientException): - """The response from the server is not valid for this request.""" - - def __init__(self, response): - super(InvalidResponse, self).__init__() - self.response = response diff --git a/keystoneclient/fixture/__init__.py b/keystoneclient/fixture/__init__.py deleted file mode 100644 index 768f9691..00000000 --- a/keystoneclient/fixture/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Produce keystone compliant structures for testing. - -The generators in this directory produce keystone compliant structures for -use in testing. -They should be considered part of the public API because they may be relied -upon to generate test tokens for other clients. However they should never be -imported into the main client (keystoneclient or other). Because of this there -may be dependencies from this module on libraries that are only available in -testing. - -.. warning:: - - The keystoneclient.fixture package is deprecated in favor of - keystoneauth1.fixture and will not be supported. - -""" - -import warnings - -from keystoneclient.fixture.discovery import * # noqa -from keystoneclient.fixture import exception -from keystoneclient.fixture import v2 -from keystoneclient.fixture import v3 - - -warnings.warn( - "The keystoneclient.fixture package is deprecated in favor of " - "keystoneauth1.fixture and will not be supported.", DeprecationWarning) - - -FixtureValidationError = exception.FixtureValidationError -V2Token = v2.Token -V3Token = v3.Token -V3FederationToken = v3.V3FederationToken - -__all__ = ('DiscoveryList', - 'FixtureValidationError', - 'V2Discovery', - 'V3Discovery', - 'V2Token', - 'V3Token', - 'V3FederationToken', - ) diff --git a/keystoneclient/fixture/discovery.py b/keystoneclient/fixture/discovery.py deleted file mode 100644 index e664d283..00000000 --- a/keystoneclient/fixture/discovery.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.fixture import discovery - - -__all__ = ('DiscoveryList', - 'V2Discovery', - 'V3Discovery', - ) - - -V2Discovery = discovery.V2Discovery -"""A Version element for a V2 identity service endpoint. - -An alias of :py:exc:`keystoneauth1.fixture.discovery.V2Discovery` -""" - -V3Discovery = discovery.V3Discovery -"""A Version element for a V3 identity service endpoint. - -An alias of :py:exc:`keystoneauth1.fixture.discovery.V3Discovery` -""" - -DiscoveryList = discovery.DiscoveryList -"""A List of version elements. - -An alias of :py:exc:`keystoneauth1.fixture.discovery.DiscoveryList` -""" diff --git a/keystoneclient/fixture/exception.py b/keystoneclient/fixture/exception.py deleted file mode 100644 index 99e48763..00000000 --- a/keystoneclient/fixture/exception.py +++ /dev/null @@ -1,20 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.fixture import exception - - -FixtureValidationError = exception.FixtureValidationError -"""The token you created is not legitimate. - -An alias of :py:exc:`keystoneauth1.fixture.exception.FixtureValidationError`` -""" diff --git a/keystoneclient/fixture/v2.py b/keystoneclient/fixture/v2.py deleted file mode 100644 index 9fbf4e00..00000000 --- a/keystoneclient/fixture/v2.py +++ /dev/null @@ -1,20 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.fixture import v2 - - -Token = v2.Token -"""A V2 Keystone token that can be used for testing. - -An alias of :py:exc:`keystoneauth1.fixture.v2.Token` -""" diff --git a/keystoneclient/fixture/v3.py b/keystoneclient/fixture/v3.py deleted file mode 100644 index 596f3e2b..00000000 --- a/keystoneclient/fixture/v3.py +++ /dev/null @@ -1,26 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.fixture import v3 - - -Token = v3.Token -"""A V3 Keystone token that can be used for testing. - -An alias of :py:exc:`keystoneauth1.fixture.v3.Token` -""" - -V3FederationToken = v3.V3FederationToken -"""A V3 Keystone Federation token that can be used for testing. - -An alias of :py:exc:`keystoneauth1.fixture.v3.V3FederationToken` -""" diff --git a/keystoneclient/generic/__init__.py b/keystoneclient/generic/__init__.py deleted file mode 100644 index 74569210..00000000 --- a/keystoneclient/generic/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ - -__all__ = ( - 'client', -) diff --git a/keystoneclient/generic/client.py b/keystoneclient/generic/client.py deleted file mode 100644 index e6b58339..00000000 --- a/keystoneclient/generic/client.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2010 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from debtcollector import removals -from six.moves.urllib import parse as urlparse - -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient.i18n import _ - - -_logger = logging.getLogger(__name__) - - -# NOTE(jamielennox): To be removed after Pike. -@removals.removed_class('keystoneclient.generic.client.Client', - message='Use keystoneauth discovery', - version='3.9.0', - removal_version='4.0.0') -class Client(httpclient.HTTPClient): - """Client for the OpenStack Keystone pre-version calls API. - - :param string endpoint: A user-supplied endpoint URL for the keystone - service. - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - - Example:: - - >>> from keystoneclient.generic import client - >>> root = client.Client(auth_url=KEYSTONE_URL) - >>> versions = root.discover() - ... - >>> from keystoneclient.v2_0 import client as v2client - >>> keystone = v2client.Client(auth_url=versions['v2.0']['url']) - ... - >>> user = keystone.users.get(USER_ID) - >>> user.delete() - - """ - - def __init__(self, endpoint=None, **kwargs): - """Initialize a new client for the Keystone v2.0 API.""" - super(Client, self).__init__(endpoint=endpoint, **kwargs) - self.endpoint = endpoint - - def discover(self, url=None): - """Discover Keystone servers and return API versions supported. - - :param url: optional url to test (without version) - - Returns:: - - { - 'message': 'Keystone found at http://127.0.0.1:5000/', - 'v2.0': { - 'status': 'beta', - 'url': 'http://127.0.0.1:5000/v2.0/', - 'id': 'v2.0' - }, - } - - """ - if url: - return self._check_keystone_versions(url) - else: - return self._local_keystone_exists() - - def _local_keystone_exists(self): - """Check if Keystone is available on default local port 35357.""" - results = self._check_keystone_versions("http://localhost:35357") - if results is None: - results = self._check_keystone_versions("https://localhost:35357") - return results - - def _check_keystone_versions(self, url): - """Call Keystone URL and detects the available API versions.""" - try: - resp, body = self._request(url, "GET", - headers={'Accept': - 'application/json'}) - # Multiple Choices status code is returned by the root - # identity endpoint, with references to one or more - # Identity API versions -- v3 spec - # some cases we get No Content - if resp.status_code in (200, 204, 300): - try: - results = {} - if 'version' in body: - results['message'] = _("Keystone found at %s") % url - version = body['version'] - # Stable/diablo incorrect format - id, status, version_url = ( - self._get_version_info(version, url)) - results[str(id)] = {"id": id, - "status": status, - "url": version_url} - return results - elif 'versions' in body: - # Correct format - results['message'] = _("Keystone found at %s") % url - for version in body['versions']['values']: - id, status, version_url = ( - self._get_version_info(version, url)) - results[str(id)] = {"id": id, - "status": status, - "url": version_url} - return results - else: - results['message'] = ( - _("Unrecognized response from %s") % url) - return results - except KeyError: - raise exceptions.AuthorizationFailure() - elif resp.status_code == 305: - return self._check_keystone_versions(resp['location']) - else: - raise exceptions.from_response(resp, "GET", url) - except Exception: - _logger.exception('Failed to detect available versions.') - - def discover_extensions(self, url=None): - """Discover Keystone extensions supported. - - :param url: optional url to test (should have a version in it) - - Returns:: - - { - 'message': 'Keystone extensions at http://127.0.0.1:35357/v2', - 'OS-KSEC2': 'OpenStack EC2 Credentials Extension', - } - - """ - if url: - return self._check_keystone_extensions(url) - - def _check_keystone_extensions(self, url): - """Call Keystone URL and detects the available extensions.""" - try: - if not url.endswith("/"): - url += '/' - resp, body = self._request("%sextensions" % url, "GET", - headers={'Accept': - 'application/json'}) - if resp.status_code in (200, 204): # some cases we get No Content - if 'extensions' in body and 'values' in body['extensions']: - # Parse correct format (per contract) - extensions = body['extensions']['values'] - elif 'extensions' in body: - # Support incorrect, but prevalent format - extensions = body['extensions'] - else: - return dict(message=( - _('Unrecognized extensions response from %s') % url)) - - return dict(self._get_extension_info(e) for e in extensions) - elif resp.status_code == 305: - return self._check_keystone_extensions(resp['location']) - else: - raise exceptions.from_response( - resp, "GET", "%sextensions" % url) - except Exception: - _logger.exception('Failed to check keystone extensions.') - - @staticmethod - def _get_version_info(version, root_url): - """Parse version information. - - :param version: a dict of a Keystone version response - :param root_url: string url used to construct - the version if no URL is provided. - :returns: tuple - (verionId, versionStatus, versionUrl) - """ - id = version['id'] - status = version['status'] - ref = urlparse.urljoin(root_url, id) - if 'links' in version: - for link in version['links']: - if link['rel'] == 'self': - ref = link['href'] - break - return (id, status, ref) - - @staticmethod - def _get_extension_info(extension): - """Parse extension information. - - :param extension: a dict of a Keystone extension response - :returns: tuple - (alias, name) - """ - alias = extension['alias'] - name = extension['name'] - return (alias, name) diff --git a/keystoneclient/httpclient.py b/keystoneclient/httpclient.py deleted file mode 100644 index e6813f32..00000000 --- a/keystoneclient/httpclient.py +++ /dev/null @@ -1,919 +0,0 @@ -# Copyright 2010 Jacob Kaplan-Moss -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Piston Cloud Computing, Inc. -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""OpenStack Client interface. Handles the REST calls and responses.""" - -import logging -import warnings - -from debtcollector import removals -from debtcollector import renames -from keystoneauth1 import adapter -from oslo_serialization import jsonutils -import pkg_resources -from positional import positional -import requests - -try: - import pickle # nosec(cjschaef): see bug 1534288 for details - - # NOTE(sdague): The conditional keyring import needs to only - # trigger if it's a version of keyring that's supported in global - # requirements. Update _min and _bad when that changes. - keyring_v = pkg_resources.parse_version( - pkg_resources.get_distribution("keyring").version) - keyring_min = pkg_resources.parse_version('5.5.1') - # This is a list of versions, e.g., pkg_resources.parse_version('3.3') - keyring_bad = [] - - if keyring_v >= keyring_min and keyring_v not in keyring_bad: - import keyring - else: - keyring = None -except (ImportError, pkg_resources.DistributionNotFound): - keyring = None - pickle = None - - -from keystoneclient import _discover -from keystoneclient import access -from keystoneclient.auth import base -from keystoneclient import baseclient -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import session as client_session - - -_logger = logging.getLogger(__name__) - -USER_AGENT = client_session.USER_AGENT -"""Default user agent string. - -This property is deprecated as of the 1.7.0 release in favor of -:data:`keystoneclient.session.USER_AGENT` and may be removed in the 2.0.0 -release. -""" - - -@removals.remove(message='Use keystoneclient.session.request instead.', - version='1.7.0', removal_version='2.0.0') -def request(*args, **kwargs): - """Make a request. - - This function is deprecated as of the 1.7.0 release in favor of - :func:`keystoneclient.session.request` and may be removed in the - 2.0.0 release. - """ - return client_session.request(*args, **kwargs) - - -class _FakeRequestSession(object): - """This object is a temporary hack that should be removed later. - - Keystoneclient has a cyclical dependency with its managers which is - preventing it from being cleaned up correctly. This is always bad but when - we switched to doing connection pooling this object wasn't getting cleaned - either and so we had left over TCP connections hanging around. - - Until we can fix the client cleanup we rollback the use of a requests - session and do individual connections like we used to. - """ - - def request(self, *args, **kwargs): - return requests.request(*args, **kwargs) - - -class _KeystoneAdapter(adapter.LegacyJsonAdapter): - """A wrapper layer to interface keystoneclient with a session. - - An adapter provides a generic interface between a client and the session to - provide client specific defaults. This object is passed to the managers. - Keystoneclient managers have some additional requirements of variables that - they expect to be present on the passed object. - - Subclass the existing adapter to provide those values that keystoneclient - managers expect. - """ - - @property - def user_id(self): - """Best effort to retrieve the user_id from the plugin. - - Some managers rely on being able to get the currently authenticated - user id. This is a problem when we are trying to abstract away the - details of an auth plugin. - - For example changing a user's password can require access to the - currently authenticated user_id. - - Perform a best attempt to fetch this data. It will work in the legacy - case and with identity plugins and be None otherwise which is the same - as the historical behavior. - """ - # the identity plugin case - try: - return self.session.auth.get_access(self.session).user_id - except AttributeError: # nosec(cjschaef): attempt legacy retrival, or - # return None - pass - - # there is a case that we explicitly allow (tested by our unit tests) - # that says you should be able to set the user_id on a legacy client - # and it should overwrite the one retrieved via authentication. If it's - # a legacy then self.session.auth is a client and we retrieve user_id. - try: - return self.session.auth.user_id - except AttributeError: # nosec(cjschaef): retrivals failed, return - # None - pass - - return None - - -class HTTPClient(baseclient.Client, base.BaseAuthPlugin): - """HTTP client. - - .. warning:: - - Creating an instance of this class without using the session argument - is deprecated as of the 1.7.0 release and may be removed in the 2.0.0 - release. - - :param string user_id: User ID for authentication. (optional) - :param string username: Username for authentication. (optional) - :param string user_domain_id: User's domain ID for authentication. - (optional) - :param string user_domain_name: User's domain name for authentication. - (optional) - :param string password: Password for authentication. (optional) - :param string domain_id: Domain ID for domain scoping. (optional) - :param string domain_name: Domain name for domain scoping. (optional) - :param string project_id: Project ID for project scoping. (optional) - :param string project_name: Project name for project scoping. (optional) - :param string project_domain_id: Project's domain ID for project scoping. - (optional) - :param string project_domain_name: Project's domain name for project - scoping. (optional) - :param string auth_url: Identity service endpoint for authorization. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - :param integer timeout: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param string endpoint: A user-supplied endpoint URL for the identity - service. Lazy-authentication is possible for API - service calls if endpoint is set at instantiation. - (optional) - :param string token: Token for authentication. (optional) - :param string cacert: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param string key: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param string cert: This argument is deprecated as of the 1.7.0 release - in favor of session and may be removed in the 2.0.0 - release. (optional) - :param boolean insecure: This argument is deprecated as of the 1.7.0 - release in favor of session and may be removed in - the 2.0.0 release. (optional) - :param string original_ip: This argument is deprecated as of the 1.7.0 - release in favor of session and may be removed - in the 2.0.0 release. (optional) - :param dict auth_ref: To allow for consumers of the client to manage their - own caching strategy, you may initialize a client - with a previously captured auth_reference (token). If - there are keyword arguments passed that also exist in - auth_ref, the value from the argument will take - precedence. - :param boolean use_keyring: Enables caching auth_ref into keyring. - default: False (optional) - :param boolean force_new_token: Keyring related parameter, forces request - for new token. default: False (optional) - :param integer stale_duration: Gap in seconds to determine if token from - keyring is about to expire. default: 30 - (optional) - :param string tenant_name: Tenant name. (optional) The tenant_name keyword - argument is deprecated as of the 1.7.0 release - in favor of project_name and may be removed in - the 2.0.0 release. - :param string tenant_id: Tenant id. (optional) The tenant_id keyword - argument is deprecated as of the 1.7.0 release in - favor of project_id and may be removed in the - 2.0.0 release. - :param string trust_id: Trust ID for trust scoping. (optional) - :param object session: A Session object to be used for - communicating with the identity service. - :type session: keystoneclient.session.Session - :param string service_name: The default service_name for URL discovery. - default: None (optional) - :param string interface: The default interface for URL discovery. - default: admin (optional) - :param string endpoint_override: Always use this endpoint URL for requests - for this client. (optional) - :param auth: An auth plugin to use instead of the session one. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - :param string user_agent: The User-Agent string to set. - default: python-keystoneclient (optional) - :param int connect_retries: the maximum number of retries that should - be attempted for connection errors. - Default None - use session default which - is don't retry. (optional) - """ - - version = None - - @renames.renamed_kwarg('tenant_name', 'project_name', version='1.7.0', - removal_version='2.0.0') - @renames.renamed_kwarg('tenant_id', 'project_id', version='1.7.0', - removal_version='2.0.0') - @positional(enforcement=positional.WARN) - def __init__(self, username=None, tenant_id=None, tenant_name=None, - password=None, auth_url=None, region_name=None, endpoint=None, - token=None, auth_ref=None, use_keyring=False, - force_new_token=False, stale_duration=None, user_id=None, - user_domain_id=None, user_domain_name=None, domain_id=None, - domain_name=None, project_id=None, project_name=None, - project_domain_id=None, project_domain_name=None, - trust_id=None, session=None, service_name=None, - interface='admin', endpoint_override=None, auth=None, - user_agent=USER_AGENT, connect_retries=None, **kwargs): - # set baseline defaults - self.user_id = None - self.username = None - self.user_domain_id = None - self.user_domain_name = None - - self.domain_id = None - self.domain_name = None - - self.project_id = None - self.project_name = None - self.project_domain_id = None - self.project_domain_name = None - - self.auth_url = None - self._endpoint = None - self._management_url = None - - self.trust_id = None - - # if loading from a dictionary passed in via auth_ref, - # load values from AccessInfo parsing that dictionary - if auth_ref: - self.auth_ref = access.AccessInfo.factory(**auth_ref) - self.version = self.auth_ref.version - self.user_id = self.auth_ref.user_id - self.username = self.auth_ref.username - self.user_domain_id = self.auth_ref.user_domain_id - self.domain_id = self.auth_ref.domain_id - self.domain_name = self.auth_ref.domain_name - self.project_id = self.auth_ref.project_id - self.project_name = self.auth_ref.project_name - self.project_domain_id = self.auth_ref.project_domain_id - auth_urls = self.auth_ref.service_catalog.get_urls( - service_type='identity', endpoint_type='public', - region_name=region_name) - self.auth_url = auth_urls[0] - management_urls = self.auth_ref.service_catalog.get_urls( - service_type='identity', endpoint_type='admin', - region_name=region_name) - self._management_url = management_urls[0] - self.auth_token_from_user = self.auth_ref.auth_token - self.trust_id = self.auth_ref.trust_id - - # TODO(blk-u): Using self.auth_ref.service_catalog._region_name is - # deprecated and this code must be removed when the property is - # actually removed. - if self.auth_ref.has_service_catalog() and not region_name: - region_name = self.auth_ref.service_catalog._region_name - - else: - self.auth_ref = None - - # allow override of the auth_ref defaults from explicit - # values provided to the client - - # apply deprecated variables first, so modern variables override them - if tenant_id: - self.project_id = tenant_id - if tenant_name: - self.project_name = tenant_name - - # user-related attributes - self.password = password - if user_id: - self.user_id = user_id - if username: - self.username = username - if user_domain_id: - self.user_domain_id = user_domain_id - elif not (user_id or user_domain_name): - self.user_domain_id = 'default' - if user_domain_name: - self.user_domain_name = user_domain_name - - # domain-related attributes - if domain_id: - self.domain_id = domain_id - if domain_name: - self.domain_name = domain_name - - # project-related attributes - if project_id: - self.project_id = project_id - if project_name: - self.project_name = project_name - if project_domain_id: - self.project_domain_id = project_domain_id - elif not (project_id or project_domain_name): - self.project_domain_id = 'default' - if project_domain_name: - self.project_domain_name = project_domain_name - - # trust-related attributes - if trust_id: - self.trust_id = trust_id - - # endpoint selection - if auth_url: - self.auth_url = auth_url.rstrip('/') - if token: - self.auth_token_from_user = token - else: - self.auth_token_from_user = None - if endpoint: - self._endpoint = endpoint.rstrip('/') - self._auth_token = None - - if not session: - - warnings.warn( - 'Constructing an HTTPClient instance without using a session ' - 'is deprecated as of the 1.7.0 release and may be removed in ' - 'the 2.0.0 release.', DeprecationWarning) - - kwargs['session'] = _FakeRequestSession() - session = client_session.Session._construct(kwargs) - session.auth = self - - self.session = session - self.domain = '' - - # NOTE(jamielennox): unfortunately we can't just use **kwargs here as - # it would incompatibly limit the kwargs that can be passed to __init__ - # try and keep this list in sync with adapter.Adapter.__init__ - version = ( - _discover.normalize_version_number(self.version) if self.version - else None) - self._adapter = _KeystoneAdapter(session, - service_type='identity', - service_name=service_name, - interface=interface, - region_name=region_name, - endpoint_override=endpoint_override, - version=version, - auth=auth, - user_agent=user_agent, - connect_retries=connect_retries) - - # keyring setup - if use_keyring and keyring is None: - _logger.warning('Failed to load keyring modules.') - self.use_keyring = use_keyring and keyring is not None - self.force_new_token = force_new_token - self.stale_duration = stale_duration or access.STALE_TOKEN_DURATION - self.stale_duration = int(self.stale_duration) - - def get_token(self, session, **kwargs): - return self.auth_token - - @property - def auth_token(self): - if self._auth_token: - return self._auth_token - if self.auth_ref: - if self.auth_ref.will_expire_soon(self.stale_duration): - self.authenticate() - return self.auth_ref.auth_token - if self.auth_token_from_user: - return self.auth_token_from_user - - def get_endpoint(self, session, interface=None, **kwargs): - if interface == 'public' or interface is base.AUTH_INTERFACE: - return self.auth_url - else: - return self.management_url - - def get_user_id(self, session, **kwargs): - return self.auth_ref.user_id - - def get_project_id(self, session, **kwargs): - return self.auth_ref.project_id - - @auth_token.setter - def auth_token(self, value): - """Override the auth_token. - - If an application sets auth_token explicitly then it will always be - used and override any past or future retrieved token. - """ - self._auth_token = value - - @auth_token.deleter - def auth_token(self): - self._auth_token = None - self.auth_token_from_user = None - - @property - def service_catalog(self): - """Return this client's service catalog.""" - try: - return self.auth_ref.service_catalog - except AttributeError: - return None - - def has_service_catalog(self): - """Return True if this client provides a service catalog.""" - return self.auth_ref and self.auth_ref.has_service_catalog() - - @property - def tenant_id(self): - """Provide read-only backwards compatibility for tenant_id. - - .. warning:: - - This is deprecated as of the 1.7.0 release in favor of project_id - and may be removed in the 2.0.0 release. - """ - warnings.warn( - 'tenant_id is deprecated as of the 1.7.0 release in favor of ' - 'project_id and may be removed in the 2.0.0 release.', - DeprecationWarning) - - return self.project_id - - @property - def tenant_name(self): - """Provide read-only backwards compatibility for tenant_name. - - .. warning:: - - This is deprecated as of the 1.7.0 release in favor of project_name - and may be removed in the 2.0.0 release. - """ - warnings.warn( - 'tenant_name is deprecated as of the 1.7.0 release in favor of ' - 'project_name and may be removed in the 2.0.0 release.', - DeprecationWarning) - - return self.project_name - - @positional(enforcement=positional.WARN) - def authenticate(self, username=None, password=None, tenant_name=None, - tenant_id=None, auth_url=None, token=None, - user_id=None, domain_name=None, domain_id=None, - project_name=None, project_id=None, user_domain_id=None, - user_domain_name=None, project_domain_id=None, - project_domain_name=None, trust_id=None, - region_name=None): - """Authenticate user. - - Uses the data provided at instantiation to authenticate against - the Identity server. This may use either a username and password - or token for authentication. If a tenant name or id was provided - then the resulting authenticated client will be scoped to that - tenant and contain a service catalog of available endpoints. - - With the v2.0 API, if a tenant name or ID is not provided, the - authentication token returned will be 'unscoped' and limited in - capabilities until a fully-scoped token is acquired. - - With the v3 API, if a domain name or id was provided then the resulting - authenticated client will be scoped to that domain. If a project name - or ID is not provided, and the authenticating user has a default - project configured, the authentication token returned will be 'scoped' - to the default project. Otherwise, the authentication token returned - will be 'unscoped' and limited in capabilities until a fully-scoped - token is acquired. - - With the v3 API, with the OS-TRUST extension enabled, the trust_id can - be provided to allow project-specific role delegation between users - - If successful, sets the self.auth_ref and self.auth_token with - the returned token. If not already set, will also set - self.management_url from the details provided in the token. - - :returns: ``True`` if authentication was successful. - :raises keystoneclient.exceptions.AuthorizationFailure: if unable to - authenticate or validate the existing authorization token - :raises keystoneclient.exceptions.ValueError: if insufficient - parameters are used. - - If keyring is used, token is retrieved from keyring instead. - Authentication will only be necessary if any of the following - conditions are met: - - * keyring is not used - * if token is not found in keyring - * if token retrieved from keyring is expired or about to - expired (as determined by stale_duration) - * if force_new_token is true - - """ - auth_url = auth_url or self.auth_url - user_id = user_id or self.user_id - username = username or self.username - password = password or self.password - - user_domain_id = user_domain_id or self.user_domain_id - user_domain_name = user_domain_name or self.user_domain_name - domain_id = domain_id or self.domain_id - domain_name = domain_name or self.domain_name - project_id = project_id or tenant_id or self.project_id - project_name = project_name or tenant_name or self.project_name - project_domain_id = project_domain_id or self.project_domain_id - project_domain_name = project_domain_name or self.project_domain_name - - trust_id = trust_id or self.trust_id - region_name = region_name or self._adapter.region_name - - if not token: - token = self.auth_token_from_user - if (not token and self.auth_ref and not - self.auth_ref.will_expire_soon(self.stale_duration)): - token = self.auth_ref.auth_token - - kwargs = { - 'auth_url': auth_url, - 'user_id': user_id, - 'username': username, - 'user_domain_id': user_domain_id, - 'user_domain_name': user_domain_name, - 'domain_id': domain_id, - 'domain_name': domain_name, - 'project_id': project_id, - 'project_name': project_name, - 'project_domain_id': project_domain_id, - 'project_domain_name': project_domain_name, - 'token': token, - 'trust_id': trust_id, - } - (keyring_key, auth_ref) = self.get_auth_ref_from_keyring(**kwargs) - new_token_needed = False - if auth_ref is None or self.force_new_token: - new_token_needed = True - kwargs['password'] = password - resp = self.get_raw_token_from_identity_service(**kwargs) - - if isinstance(resp, access.AccessInfo): - self.auth_ref = resp - else: - self.auth_ref = access.AccessInfo.factory(*resp) - - # NOTE(jamielennox): The original client relies on being able to - # push the region name into the service catalog but new auth - # it in. - if region_name: - self.auth_ref.service_catalog._region_name = region_name - else: - self.auth_ref = auth_ref - - self.process_token(region_name=region_name) - if new_token_needed: - self.store_auth_ref_into_keyring(keyring_key) - return True - - def _build_keyring_key(self, **kwargs): - """Create a unique key for keyring. - - Used to store and retrieve auth_ref from keyring. - - Return a slash-separated string of values ordered by key name. - - """ - return '/'.join([kwargs[k] or '?' for k in sorted(kwargs)]) - - def get_auth_ref_from_keyring(self, **kwargs): - """Retrieve auth_ref from keyring. - - If auth_ref is found in keyring, (keyring_key, auth_ref) is returned. - Otherwise, (keyring_key, None) is returned. - - :returns: (keyring_key, auth_ref) or (keyring_key, None) - :returns: or (None, None) if use_keyring is not set in the object - - """ - keyring_key = None - auth_ref = None - if self.use_keyring: - keyring_key = self._build_keyring_key(**kwargs) - try: - auth_ref = keyring.get_password("keystoneclient_auth", - keyring_key) - if auth_ref: - auth_ref = pickle.loads(auth_ref) # nosec(cjschaef): see - # bug 1534288 - if auth_ref.will_expire_soon(self.stale_duration): - # token has expired, don't use it - auth_ref = None - except Exception as e: - auth_ref = None - _logger.warning('Unable to retrieve token from keyring %s', e) - return (keyring_key, auth_ref) - - def store_auth_ref_into_keyring(self, keyring_key): - """Store auth_ref into keyring.""" - if self.use_keyring: - try: - keyring.set_password("keystoneclient_auth", - keyring_key, - pickle.dumps(self.auth_ref)) # nosec - # (cjschaef): see bug 1534288 - except Exception as e: - _logger.warning("Failed to store token into keyring %s", e) - - def _process_management_url(self, region_name): - try: - self._management_url = self.auth_ref.service_catalog.url_for( - service_type='identity', - endpoint_type='admin', - region_name=region_name) - except exceptions.EndpointNotFound as e: - _logger.debug("Failed to find endpoint for management url %s", e) - - def process_token(self, region_name=None): - """Extract and process information from the new auth_ref. - - And set the relevant authentication information. - """ - # if we got a response without a service catalog, set the local - # list of tenants for introspection, and leave to client user - # to determine what to do. Otherwise, load up the service catalog - if self.auth_ref.project_scoped: - if not self.auth_ref.tenant_id: - raise exceptions.AuthorizationFailure( - _("Token didn't provide tenant_id")) - self._process_management_url(region_name) - self.project_name = self.auth_ref.tenant_name - self.project_id = self.auth_ref.tenant_id - - if not self.auth_ref.user_id: - raise exceptions.AuthorizationFailure( - _("Token didn't provide user_id")) - - self.user_id = self.auth_ref.user_id - - self.auth_domain_id = self.auth_ref.domain_id - self.auth_tenant_id = self.auth_ref.tenant_id - self.auth_user_id = self.auth_ref.user_id - - @property - def management_url(self): - return self._endpoint or self._management_url - - @management_url.setter - def management_url(self, value): - # NOTE(jamielennox): it's debatable here whether we should set - # _endpoint or _management_url. As historically management_url was set - # permanently setting _endpoint would better match that behaviour. - self._endpoint = value - - @positional(enforcement=positional.WARN) - def get_raw_token_from_identity_service(self, auth_url, username=None, - password=None, tenant_name=None, - tenant_id=None, token=None, - user_id=None, user_domain_id=None, - user_domain_name=None, - domain_id=None, domain_name=None, - project_id=None, project_name=None, - project_domain_id=None, - project_domain_name=None, - trust_id=None): - """Authenticate against the Identity API and get a token. - - Not implemented here because auth protocols should be API - version-specific. - - Expected to authenticate or validate an existing authentication - reference already associated with the client. Invoking this call - *always* makes a call to the Identity service. - - :returns: (``resp``, ``body``) - - """ - raise NotImplementedError - - def serialize(self, entity): - return jsonutils.dumps(entity) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def request(self, *args, **kwargs): - """Send an http request with the specified characteristics. - - Wrapper around requests.request to handle tasks such as - setting headers, JSON encoding/decoding, and error handling. - - .. warning:: - - *DEPRECATED*: This function is no longer used. It was designed to - be used only by the managers and the managers now receive an - adapter so this function is no longer on the standard request path. - This may be removed in the 2.0.0 release. - """ - return self._request(*args, **kwargs) - - def _request(self, *args, **kwargs): - kwargs.setdefault('authenticated', False) - return self._adapter.request(*args, **kwargs) - - def _cs_request(self, url, method, management=True, **kwargs): - """Make an authenticated request to keystone endpoint. - - Request are made to keystone endpoint by concatenating - self.management_url and url and passing in method and - any associated kwargs. - """ - if not management: - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - endpoint_filter.setdefault('interface', 'public') - - kwargs.setdefault('authenticated', None) - return self._request(url, method, **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def get(self, url, **kwargs): - """Perform an authenticated GET request. - - This calls :py:meth:`.request()` with ``method`` set to ``GET`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'GET', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def head(self, url, **kwargs): - """Perform an authenticated HEAD request. - - This calls :py:meth:`.request()` with ``method`` set to ``HEAD`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'HEAD', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def post(self, url, **kwargs): - """Perform an authenticate POST request. - - This calls :py:meth:`.request()` with ``method`` set to ``POST`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'POST', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def put(self, url, **kwargs): - """Perform an authenticate PUT request. - - This calls :py:meth:`.request()` with ``method`` set to ``PUT`` and an - authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'PUT', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def patch(self, url, **kwargs): - """Perform an authenticate PATCH request. - - This calls :py:meth:`.request()` with ``method`` set to ``PATCH`` and - an authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'PATCH', **kwargs) - - @removals.remove(version='1.7.0', removal_version='2.0.0') - def delete(self, url, **kwargs): - """Perform an authenticate DELETE request. - - This calls :py:meth:`.request()` with ``method`` set to ``DELETE`` and - an authentication token if one is available. - - .. warning:: - - *DEPRECATED*: This function is no longer used and is deprecated as - of the 1.7.0 release and may be removed in the 2.0.0 release. It - was designed to be used by the managers and the managers now - receive an adapter so this function is no longer on the standard - request path. - """ - return self._cs_request(url, 'DELETE', **kwargs) - - deprecated_session_variables = {'original_ip': None, - 'cert': None, - 'timeout': None, - 'verify_cert': 'verify'} - - deprecated_adapter_variables = {'region_name': None} - - def __getattr__(self, name): - """Fetch deprecated session variables.""" - try: - var_name = self.deprecated_session_variables[name] - except KeyError: # nosec(cjschaef): try adapter variable or raise - # an AttributeError - pass - else: - warnings.warn( - 'The %s session variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return getattr(self.session, var_name or name) - - try: - var_name = self.deprecated_adapter_variables[name] - except KeyError: # nosec(cjschaef): raise an AttributeError - pass - else: - warnings.warn( - 'The %s adapter variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return getattr(self._adapter, var_name or name) - - raise AttributeError(_("Unknown Attribute: %s") % name) - - def __setattr__(self, name, val): - """Assign value to deprecated seesion variables.""" - try: - var_name = self.deprecated_session_variables[name] - except KeyError: # nosec(cjschaef): try adapter variable or call - # parent class's __setattr__ - pass - else: - warnings.warn( - 'The %s session variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return setattr(self.session, var_name or name) - - try: - var_name = self.deprecated_adapter_variables[name] - except KeyError: # nosec(cjschaef): call parent class's __setattr__ - pass - else: - warnings.warn( - 'The %s adapter variable is deprecated as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release' % name, - DeprecationWarning) - return setattr(self._adapter, var_name or name) - - super(HTTPClient, self).__setattr__(name, val) diff --git a/keystoneclient/i18n.py b/keystoneclient/i18n.py deleted file mode 100644 index f3726d19..00000000 --- a/keystoneclient/i18n.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""oslo.i18n integration module. - -See https://docs.openstack.org/oslo.i18n/latest/user/index.html . - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='keystoneclient') - -# The primary translation function using the well-known name "_" -_ = _translators.primary diff --git a/keystoneclient/service_catalog.py b/keystoneclient/service_catalog.py deleted file mode 100644 index 45d7d0a6..00000000 --- a/keystoneclient/service_catalog.py +++ /dev/null @@ -1,432 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011, Piston Cloud Computing, Inc. -# Copyright 2011 Nebula, Inc. -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import abc -import warnings - -from positional import positional -import six - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -@six.add_metaclass(abc.ABCMeta) -class ServiceCatalog(object): - """Helper methods for dealing with a Keystone Service Catalog. - - .. warning:: - - Setting region_name is deprecated in favor of passing the region name - as a parameter to calls made to the service catalog as of the 1.7.0 - release and may be removed in the 2.0.0 release. - - """ - - @classmethod - def factory(cls, resource_dict, token=None, region_name=None): - """Create ServiceCatalog object given an auth token. - - .. warning:: - - Setting region_name is deprecated in favor of passing the region - name as a parameter to calls made to the service catalog as of the - 1.7.0 release and may be removed in the 2.0.0 release. - - """ - if ServiceCatalogV3.is_valid(resource_dict): - return ServiceCatalogV3(token, resource_dict, region_name) - elif ServiceCatalogV2.is_valid(resource_dict): - return ServiceCatalogV2(resource_dict, region_name) - else: - raise NotImplementedError(_('Unrecognized auth response')) - - def __init__(self, region_name=None): - if region_name: - warnings.warn( - 'Setting region_name on the service catalog is deprecated in ' - 'favor of passing the region name as a parameter to calls ' - 'made to the service catalog as of the 1.7.0 release and may ' - 'be removed in the 2.0.0 release.', - DeprecationWarning) - - self._region_name = region_name - - @property - def region_name(self): - """Region name. - - .. warning:: - - region_name is deprecated in favor of passing the region name as a - parameter to calls made to the service catalog as of the 1.7.0 - release and may be removed in the 2.0.0 release. - - """ - warnings.warn( - 'region_name is deprecated in favor of passing the region name as ' - 'a parameter to calls made to the service catalog as of the 1.7.0 ' - 'release and may be removed in the 2.0.0 release.', - DeprecationWarning) - return self._region_name - - def _get_endpoint_region(self, endpoint): - return endpoint.get('region_id') or endpoint.get('region') - - @abc.abstractmethod - def get_token(self): - """Fetch token details from service catalog. - - Returns a dictionary containing the following:: - - - `id`: Token's ID - - `expires`: Token's expiration - - `user_id`: Authenticated user's ID - - `tenant_id`: Authorized project's ID - - `domain_id`: Authorized domain's ID - - """ - raise NotImplementedError() # pragma: no cover - - @abc.abstractmethod - def _is_endpoint_type_match(self, endpoint, endpoint_type): - """Helper function to normalize endpoint matching across v2 and v3. - - :returns: True if the provided endpoint matches the required - endpoint_type otherwise False. - """ - pass # pragma: no cover - - @abc.abstractmethod - def _normalize_endpoint_type(self, endpoint_type): - """Handle differences in the way v2 and v3 catalogs specify endpoint. - - Both v2 and v3 must be able to handle the endpoint style of the other. - For example v2 must be able to handle a 'public' endpoint_type and - v3 must be able to handle a 'publicURL' endpoint_type. - - :returns: the endpoint string in the format appropriate for this - service catalog. - """ - pass # pragma: no cover - - def get_endpoints(self, service_type=None, endpoint_type=None, - region_name=None, service_name=None): - """Fetch and filter endpoints for the specified service(s). - - Returns endpoints for the specified service (or all) containing - the specified type (or all) and region (or all) and service name. - - If there is no name in the service catalog the service_name check will - be skipped. This allows compatibility with services that existed - before the name was available in the catalog. - """ - endpoint_type = self._normalize_endpoint_type(endpoint_type) - region_name = region_name or self._region_name - - sc = {} - - for service in (self.get_data() or []): - try: - st = service['type'] - except KeyError: - continue - - if service_type and service_type != st: - continue - - # NOTE(jamielennox): service_name is different. It is not available - # in API < v3.3. If it is in the catalog then we enforce it, if it - # is not then we don't because the name could be correct we just - # don't have that information to check against. - if service_name: - try: - sn = service['name'] - except KeyError: # nosec(cjschaef) - # assume that we're in v3.0-v3.2 and don't have the name in - # the catalog. Skip the check. - pass - else: - if service_name != sn: - continue - - endpoints = sc.setdefault(st, []) - - for endpoint in service.get('endpoints', []): - if (endpoint_type and not - self._is_endpoint_type_match(endpoint, endpoint_type)): - continue - if (region_name and - region_name != self._get_endpoint_region(endpoint)): - continue - endpoints.append(endpoint) - - return sc - - def _get_service_endpoints(self, attr, filter_value, service_type, - endpoint_type, region_name, service_name): - """Fetch the endpoints of a particular service_type. - - Endpoints returned are also filtered based on the attr and - filter_value provided. - """ - sc_endpoints = self.get_endpoints(service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - try: - endpoints = sc_endpoints[service_type] - except KeyError: - return - - if attr and not filter_value: - warnings.warn( - 'Providing attr without filter_value to get_urls() is ' - 'deprecated as of the 1.7.0 release and may be removed in the ' - '2.0.0 release. Either both should be provided or neither ' - 'should be provided.') - - if filter_value: - return [endpoint for endpoint in endpoints - if endpoint.get(attr) == filter_value] - - return endpoints - - @abc.abstractmethod - @positional(enforcement=positional.WARN) - def get_urls(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL', - region_name=None, service_name=None): - """Fetch endpoint urls from the service catalog. - - Fetch the endpoints from the service catalog for a particular - endpoint attribute. If no attribute is given, return the first - endpoint of the specified type. - - :param string attr: Endpoint attribute name. - :param string filter_value: Endpoint attribute value. - :param string service_type: Service type of the endpoint. - :param string endpoint_type: Type of endpoint. - Possible values: public or publicURL, - internal or internalURL, admin or - adminURL - :param string region_name: Region of the endpoint. - :param string service_name: The assigned name of the service. - - :returns: tuple of urls or None (if no match found) - """ - raise NotImplementedError() # pragma: no cover - - @positional(3, enforcement=positional.WARN) - def url_for(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL', - region_name=None, service_name=None): - """Fetch an endpoint from the service catalog. - - Fetch the specified endpoint from the service catalog for - a particular endpoint attribute. If no attribute is given, return - the first endpoint of the specified type. - - Valid endpoint types: `public` or `publicURL`, - `internal` or `internalURL`, - `admin` or 'adminURL` - - :param string attr: Endpoint attribute name. - :param string filter_value: Endpoint attribute value. - :param string service_type: Service type of the endpoint. - :param string endpoint_type: Type of endpoint. - :param string region_name: Region of the endpoint. - :param string service_name: The assigned name of the service. - - """ - if not self.get_data(): - raise exceptions.EmptyCatalog(_('The service catalog is empty.')) - - urls = self.get_urls(attr=attr, - filter_value=filter_value, - service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - try: - return urls[0] - except Exception: - if service_name and region_name: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service named %(service_name)s in %(region_name)s ' - 'region not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type, - 'service_name': service_name, - 'region_name': region_name}) - elif service_name: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service named %(service_name)s not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type, - 'service_name': service_name}) - elif region_name: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service in %(region_name)s region not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type, - 'region_name': region_name}) - else: - msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' - 'service not found') % - {'endpoint_type': endpoint_type, - 'service_type': service_type}) - - raise exceptions.EndpointNotFound(msg) - - @abc.abstractmethod - def get_data(self): - """Get the raw catalog structure. - - Get the version dependent catalog structure as it is presented within - the resource. - - :returns: list containing raw catalog data entries or None - """ - raise NotImplementedError() # pragma: no cover - - -class ServiceCatalogV2(ServiceCatalog): - """An object for encapsulating the v2 service catalog. - - The object is created using raw v2 auth token from Keystone. - """ - - def __init__(self, resource_dict, region_name=None): - self.catalog = resource_dict - super(ServiceCatalogV2, self).__init__(region_name=region_name) - - @classmethod - def is_valid(cls, resource_dict): - # This class is also used for reading token info of an unscoped token. - # Unscoped token does not have 'serviceCatalog' in V2, checking this - # will not work. Use 'token' attribute instead. - return 'token' in resource_dict - - def _normalize_endpoint_type(self, endpoint_type): - if endpoint_type and 'URL' not in endpoint_type: - endpoint_type += 'URL' - - return endpoint_type - - def _is_endpoint_type_match(self, endpoint, endpoint_type): - return endpoint_type in endpoint - - def get_data(self): - return self.catalog.get('serviceCatalog') - - def get_token(self): - token = {'id': self.catalog['token']['id'], - 'expires': self.catalog['token']['expires']} - try: - token['user_id'] = self.catalog['user']['id'] - token['tenant_id'] = self.catalog['token']['tenant']['id'] - except KeyError: # nosec(cjschaef) - # just leave the tenant and user out if it doesn't exist - pass - return token - - @positional(enforcement=positional.WARN) - def get_urls(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL', - region_name=None, service_name=None): - endpoint_type = self._normalize_endpoint_type(endpoint_type) - endpoints = self._get_service_endpoints(attr=attr, - filter_value=filter_value, - service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - if endpoints: - return tuple([endpoint[endpoint_type] for endpoint in endpoints]) - else: - return None - - -class ServiceCatalogV3(ServiceCatalog): - """An object for encapsulating the v3 service catalog. - - The object is created using raw v3 auth token from Keystone. - """ - - def __init__(self, token, resource_dict, region_name=None): - super(ServiceCatalogV3, self).__init__(region_name=region_name) - self._auth_token = token - self.catalog = resource_dict - - @classmethod - def is_valid(cls, resource_dict): - # This class is also used for reading token info of an unscoped token. - # Unscoped token does not have 'catalog', checking this - # will not work. Use 'methods' attribute instead. - return 'methods' in resource_dict - - def _normalize_endpoint_type(self, endpoint_type): - if endpoint_type: - endpoint_type = endpoint_type.rstrip('URL') - - return endpoint_type - - def _is_endpoint_type_match(self, endpoint, endpoint_type): - try: - return endpoint_type == endpoint['interface'] - except KeyError: - return False - - def get_data(self): - return self.catalog.get('catalog') - - def get_token(self): - token = {'id': self._auth_token, - 'expires': self.catalog['expires_at']} - try: - token['user_id'] = self.catalog['user']['id'] - domain = self.catalog.get('domain') - if domain: - token['domain_id'] = domain['id'] - project = self.catalog.get('project') - if project: - token['tenant_id'] = project['id'] - except KeyError: # nosec(cjschaef) - # just leave the domain, project and user out if it doesn't exist - pass - return token - - @positional(enforcement=positional.WARN) - def get_urls(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='public', - region_name=None, service_name=None): - endpoints = self._get_service_endpoints(attr=attr, - filter_value=filter_value, - service_type=service_type, - endpoint_type=endpoint_type, - region_name=region_name, - service_name=service_name) - - if endpoints: - return tuple([endpoint['url'] for endpoint in endpoints]) - else: - return None diff --git a/keystoneclient/session.py b/keystoneclient/session.py deleted file mode 100644 index 9faedacd..00000000 --- a/keystoneclient/session.py +++ /dev/null @@ -1,1020 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import functools -import hashlib -import logging -import os -import socket -import time -import warnings - -from debtcollector import removals -from oslo_config import cfg -from oslo_serialization import jsonutils -from oslo_utils import encodeutils -from oslo_utils import importutils -from oslo_utils import strutils -from positional import positional -import requests -import six -from six.moves import urllib - -from keystoneclient import exceptions -from keystoneclient.i18n import _ - -osprofiler_web = importutils.try_import("osprofiler.web") - -USER_AGENT = 'python-keystoneclient' - -# NOTE(jamielennox): Clients will likely want to print more than json. Please -# propose a patch if you have a content type you think is reasonable to print -# here and we'll add it to the list as required. -_LOG_CONTENT_TYPES = set(['application/json']) - -_logger = logging.getLogger(__name__) - - -def _positive_non_zero_float(argument_value): - if argument_value is None: - return None - try: - value = float(argument_value) - except ValueError: - msg = _("%s must be a float") % argument_value - raise argparse.ArgumentTypeError(msg) - if value <= 0: - msg = _("%s must be greater than 0") % argument_value - raise argparse.ArgumentTypeError(msg) - return value - - -def request(url, method='GET', **kwargs): - return Session().request(url, method=method, **kwargs) - - -def _remove_service_catalog(body): - try: - data = jsonutils.loads(body) - - # V3 token - if 'token' in data and 'catalog' in data['token']: - data['token']['catalog'] = '' - return jsonutils.dumps(data) - - # V2 token - if 'serviceCatalog' in data['access']: - data['access']['serviceCatalog'] = '' - return jsonutils.dumps(data) - - except Exception: # nosec(cjschaef): multiple exceptions can be raised - # Don't fail trying to clean up the request body. - pass - return body - - -class Session(object): - """Maintains client communication state and common functionality. - - As much as possible the parameters to this class reflect and are passed - directly to the requests library. - - :param auth: An authentication plugin to authenticate the session with. - (optional, defaults to None) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - :param requests.Session session: A requests session object that can be used - for issuing requests. (optional) - :param string original_ip: The original IP of the requesting user which - will be sent to identity service in a - 'Forwarded' header. (optional) - :param verify: The verification arguments to pass to requests. These are of - the same form as requests expects, so True or False to - verify (or not) against system certificates or a path to a - bundle or CA certs to check against or None for requests to - attempt to locate and use certificates. (optional, defaults - to True) - :param cert: A client certificate to pass to requests. These are of the - same form as requests expects. Either a single filename - containing both the certificate and key or a tuple containing - the path to the certificate then a path to the key. (optional) - :param float timeout: A timeout to pass to requests. This should be a - numerical value indicating some amount (or fraction) - of seconds or 0 for no timeout. (optional, defaults - to 0) - :param string user_agent: A User-Agent header string to use for the - request. If not provided a default is used. - (optional, defaults to 'python-keystoneclient') - :param int/bool redirect: Controls the maximum number of redirections that - can be followed by a request. Either an integer - for a specific count or True/False for - forever/never. (optional, default to 30) - """ - - user_agent = None - - _REDIRECT_STATUSES = (301, 302, 303, 305, 307) - - REDIRECT_STATUSES = _REDIRECT_STATUSES - """This property is deprecated as of the 1.7.0 release and may be removed - in the 2.0.0 release.""" - - _DEFAULT_REDIRECT_LIMIT = 30 - - DEFAULT_REDIRECT_LIMIT = _DEFAULT_REDIRECT_LIMIT - """This property is deprecated as of the 1.7.0 release and may be removed - in the 2.0.0 release.""" - - @positional(2, enforcement=positional.WARN) - def __init__(self, auth=None, session=None, original_ip=None, verify=True, - cert=None, timeout=None, user_agent=None, - redirect=_DEFAULT_REDIRECT_LIMIT): - warnings.warn( - 'keystoneclient.session.Session is deprecated as of the 2.1.0 ' - 'release in favor of keystoneauth1.session.Session. It will be ' - 'removed in future releases.', - DeprecationWarning) - - if not session: - session = requests.Session() - # Use TCPKeepAliveAdapter to fix bug 1323862 - for scheme in list(session.adapters): - session.mount(scheme, TCPKeepAliveAdapter()) - - self.auth = auth - self.session = session - self.original_ip = original_ip - self.verify = verify - self.cert = cert - self.timeout = None - self.redirect = redirect - - if timeout is not None: - self.timeout = float(timeout) - - # don't override the class variable if none provided - if user_agent is not None: - self.user_agent = user_agent - - @staticmethod - def _process_header(header): - """Redact the secure headers to be logged.""" - secure_headers = ('authorization', 'x-auth-token', - 'x-subject-token', 'x-service-token') - if header[0].lower() in secure_headers: - token_hasher = hashlib.sha1() - token_hasher.update(header[1].encode('utf-8')) - token_hash = token_hasher.hexdigest() - return (header[0], '{SHA1}%s' % token_hash) - return header - - @positional() - def _http_log_request(self, url, method=None, data=None, - headers=None, logger=_logger): - if not logger.isEnabledFor(logging.DEBUG): - # NOTE(morganfainberg): This whole debug section is expensive, - # there is no need to do the work if we're not going to emit a - # debug log. - return - - string_parts = ['REQ: curl -g -i'] - - # NOTE(jamielennox): None means let requests do its default validation - # so we need to actually check that this is False. - if self.verify is False: - string_parts.append('--insecure') - elif isinstance(self.verify, six.string_types): - string_parts.append('--cacert "%s"' % self.verify) - - if method: - string_parts.extend(['-X', method]) - - string_parts.append(url) - - if headers: - for header in headers.items(): - string_parts.append('-H "%s: %s"' - % self._process_header(header)) - - if data: - if isinstance(data, six.binary_type): - try: - data = data.decode("ascii") - except UnicodeDecodeError: - data = "" - string_parts.append("-d '%s'" % data) - try: - logger.debug(' '.join(string_parts)) - except UnicodeDecodeError: - logger.debug("Replaced characters that could not be decoded" - " in log output, original caused UnicodeDecodeError") - string_parts = [ - encodeutils.safe_decode( - part, errors='replace') for part in string_parts] - logger.debug(' '.join(string_parts)) - - def _http_log_response(self, response, logger): - if not logger.isEnabledFor(logging.DEBUG): - return - - # NOTE(samueldmq): If the response does not provide enough info about - # the content type to decide whether it is useful and safe to log it - # or not, just do not log the body. Trying to# read the response body - # anyways may result on reading a long stream of bytes and getting an - # unexpected MemoryError. See bug 1616105 for further details. - content_type = response.headers.get('content-type', None) - - # NOTE(lamt): Per [1], the Content-Type header can be of the form - # Content-Type := type "/" subtype *[";" parameter] - # [1] https://www.w3.org/Protocols/rfc1341/4_Content-Type.html - for log_type in _LOG_CONTENT_TYPES: - if content_type is not None and content_type.startswith(log_type): - text = _remove_service_catalog(response.text) - break - else: - text = ('Omitted, Content-Type is set to %s. Only ' - '%s responses have their bodies logged.') - text = text % (content_type, ', '.join(_LOG_CONTENT_TYPES)) - - string_parts = [ - 'RESP:', - '[%s]' % response.status_code - ] - for header in response.headers.items(): - string_parts.append('%s: %s' % self._process_header(header)) - string_parts.append('\nRESP BODY: %s\n' % strutils.mask_password(text)) - - logger.debug(' '.join(string_parts)) - - # NOTE(artmr): parameter 'original_ip' value is never used - @positional(enforcement=positional.WARN) - def request(self, url, method, json=None, original_ip=None, - user_agent=None, redirect=None, authenticated=None, - endpoint_filter=None, auth=None, requests_auth=None, - raise_exc=True, allow_reauth=True, log=True, - endpoint_override=None, connect_retries=0, logger=_logger, - **kwargs): - """Send an HTTP request with the specified characteristics. - - Wrapper around `requests.Session.request` to handle tasks such as - setting headers, JSON encoding/decoding, and error handling. - - Arguments that are not handled are passed through to the requests - library. - - :param string url: Path or fully qualified URL of HTTP request. If only - a path is provided then endpoint_filter must also be - provided such that the base URL can be determined. - If a fully qualified URL is provided then - endpoint_filter will be ignored. - :param string method: The http method to use. (e.g. 'GET', 'POST') - :param string original_ip: Mark this request as forwarded for this ip. - (optional) - :param dict headers: Headers to be included in the request. (optional) - :param json: Some data to be represented as JSON. (optional) - :param string user_agent: A user_agent to use for the request. If - present will override one present in headers. - (optional) - :param int/bool redirect: the maximum number of redirections that - can be followed by a request. Either an - integer for a specific count or True/False - for forever/never. (optional) - :param int connect_retries: the maximum number of retries that should - be attempted for connection errors. - (optional, defaults to 0 - never retry). - :param bool authenticated: True if a token should be attached to this - request, False if not or None for attach if - an auth_plugin is available. - (optional, defaults to None) - :param dict endpoint_filter: Data to be provided to an auth plugin with - which it should be able to determine an - endpoint to use for this request. If not - provided then URL is expected to be a - fully qualified URL. (optional) - :param str endpoint_override: The URL to use instead of looking up the - endpoint in the auth plugin. This will be - ignored if a fully qualified URL is - provided but take priority over an - endpoint_filter. (optional) - :param auth: The auth plugin to use when authenticating this request. - This will override the plugin that is attached to the - session (if any). (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - :param requests_auth: A requests library auth plugin that cannot be - passed via kwarg because the `auth` kwarg - collides with our own auth plugins. (optional) - :type requests_auth: :py:class:`requests.auth.AuthBase` - :param bool raise_exc: If True then raise an appropriate exception for - failed HTTP requests. If False then return the - request object. (optional, default True) - :param bool allow_reauth: Allow fetching a new token and retrying the - request on receiving a 401 Unauthorized - response. (optional, default True) - :param bool log: If True then log the request and response data to the - debug log. (optional, default True) - :param logger: The logger object to use to log request and responses. - If not provided the keystoneclient.session default - logger will be used. - :type logger: logging.Logger - :param kwargs: any other parameter that can be passed to - requests.Session.request (such as `headers`). Except: - 'data' will be overwritten by the data in 'json' param. - 'allow_redirects' is ignored as redirects are handled - by the session. - - :raises keystoneclient.exceptions.ClientException: For connection - failure, or to indicate an error response code. - - :returns: The response to the request. - """ - headers = kwargs.setdefault('headers', dict()) - - if authenticated is None: - authenticated = bool(auth or self.auth) - - if authenticated: - auth_headers = self.get_auth_headers(auth) - - if auth_headers is None: - msg = _('No valid authentication is available') - raise exceptions.AuthorizationFailure(msg) - - headers.update(auth_headers) - - if osprofiler_web: - headers.update(osprofiler_web.get_trace_id_headers()) - - # if we are passed a fully qualified URL and an endpoint_filter we - # should ignore the filter. This will make it easier for clients who - # want to overrule the default endpoint_filter data added to all client - # requests. We check fully qualified here by the presence of a host. - if not urllib.parse.urlparse(url).netloc: - base_url = None - - if endpoint_override: - base_url = endpoint_override - elif endpoint_filter: - base_url = self.get_endpoint(auth, **endpoint_filter) - - if not base_url: - service_type = (endpoint_filter or {}).get('service_type', - 'unknown') - msg = _('Endpoint for %s service') % service_type - raise exceptions.EndpointNotFound(msg) - - url = '%s/%s' % (base_url.rstrip('/'), url.lstrip('/')) - - if self.cert: - kwargs.setdefault('cert', self.cert) - - if self.timeout is not None: - kwargs.setdefault('timeout', self.timeout) - - if user_agent: - headers['User-Agent'] = user_agent - elif self.user_agent: - user_agent = headers.setdefault('User-Agent', self.user_agent) - else: - user_agent = headers.setdefault('User-Agent', USER_AGENT) - - if self.original_ip: - headers.setdefault('Forwarded', - 'for=%s;by=%s' % (self.original_ip, user_agent)) - - if json is not None: - headers['Content-Type'] = 'application/json' - kwargs['data'] = jsonutils.dumps(json) - - kwargs.setdefault('verify', self.verify) - - if requests_auth: - kwargs['auth'] = requests_auth - - if log: - self._http_log_request(url, method=method, - data=kwargs.get('data'), - headers=headers, - logger=logger) - - # Force disable requests redirect handling. We will manage this below. - kwargs['allow_redirects'] = False - - if redirect is None: - redirect = self.redirect - - send = functools.partial(self._send_request, - url, method, redirect, log, logger, - connect_retries) - - try: - connection_params = self.get_auth_connection_params(auth=auth) - except exceptions.MissingAuthPlugin: # nosec(cjschaef) - # NOTE(jamielennox): If we've gotten this far without an auth - # plugin then we should be happy with allowing no additional - # connection params. This will be the typical case for plugins - # anyway. - pass - else: - if connection_params: - kwargs.update(connection_params) - - resp = send(**kwargs) - - # handle getting a 401 Unauthorized response by invalidating the plugin - # and then retrying the request. This is only tried once. - if resp.status_code == 401 and authenticated and allow_reauth: - if self.invalidate(auth): - auth_headers = self.get_auth_headers(auth) - - if auth_headers is not None: - headers.update(auth_headers) - resp = send(**kwargs) - - if raise_exc and resp.status_code >= 400: - logger.debug('Request returned failure status: %s', - resp.status_code) - raise exceptions.from_response(resp, method, url) - - return resp - - def _send_request(self, url, method, redirect, log, logger, - connect_retries, connect_retry_delay=0.5, **kwargs): - # NOTE(jamielennox): We handle redirection manually because the - # requests lib follows some browser patterns where it will redirect - # POSTs as GETs for certain statuses which is not want we want for an - # API. See: https://en.wikipedia.org/wiki/Post/Redirect/Get - - # NOTE(jamielennox): The interaction between retries and redirects are - # handled naively. We will attempt only a maximum number of retries and - # redirects rather than per request limits. Otherwise the extreme case - # could be redirects * retries requests. This will be sufficient in - # most cases and can be fixed properly if there's ever a need. - - try: - try: - resp = self.session.request(method, url, **kwargs) - except requests.exceptions.SSLError as e: - msg = _('SSL exception connecting to %(url)s: ' - '%(error)s') % {'url': url, 'error': e} - raise exceptions.SSLError(msg) - except requests.exceptions.Timeout: - msg = _('Request to %s timed out') % url - raise exceptions.RequestTimeout(msg) - except requests.exceptions.ConnectionError: - msg = _('Unable to establish connection to %s') % url - raise exceptions.ConnectionRefused(msg) - except (exceptions.RequestTimeout, exceptions.ConnectionRefused) as e: - if connect_retries <= 0: - raise - - logger.info('Failure: %(e)s. Retrying in %(delay).1fs.', - {'e': e, 'delay': connect_retry_delay}) - time.sleep(connect_retry_delay) - - return self._send_request( - url, method, redirect, log, logger, - connect_retries=connect_retries - 1, - connect_retry_delay=connect_retry_delay * 2, - **kwargs) - - if log: - self._http_log_response(resp, logger) - - if resp.status_code in self._REDIRECT_STATUSES: - # be careful here in python True == 1 and False == 0 - if isinstance(redirect, bool): - redirect_allowed = redirect - else: - redirect -= 1 - redirect_allowed = redirect >= 0 - - if not redirect_allowed: - return resp - - try: - location = resp.headers['location'] - except KeyError: - logger.warning("Failed to redirect request to %s as new " - "location was not provided.", resp.url) - else: - # NOTE(jamielennox): We don't pass through connect_retry_delay. - # This request actually worked so we can reset the delay count. - new_resp = self._send_request( - location, method, redirect, log, logger, - connect_retries=connect_retries, - **kwargs) - - if not isinstance(new_resp.history, list): - new_resp.history = list(new_resp.history) - new_resp.history.insert(0, resp) - resp = new_resp - - return resp - - def head(self, url, **kwargs): - """Perform a HEAD request. - - This calls :py:meth:`.request()` with ``method`` set to ``HEAD``. - - """ - return self.request(url, 'HEAD', **kwargs) - - def get(self, url, **kwargs): - """Perform a GET request. - - This calls :py:meth:`.request()` with ``method`` set to ``GET``. - - """ - return self.request(url, 'GET', **kwargs) - - def post(self, url, **kwargs): - """Perform a POST request. - - This calls :py:meth:`.request()` with ``method`` set to ``POST``. - - """ - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - """Perform a PUT request. - - This calls :py:meth:`.request()` with ``method`` set to ``PUT``. - - """ - return self.request(url, 'PUT', **kwargs) - - def delete(self, url, **kwargs): - """Perform a DELETE request. - - This calls :py:meth:`.request()` with ``method`` set to ``DELETE``. - - """ - return self.request(url, 'DELETE', **kwargs) - - def patch(self, url, **kwargs): - """Perform a PATCH request. - - This calls :py:meth:`.request()` with ``method`` set to ``PATCH``. - - """ - return self.request(url, 'PATCH', **kwargs) - - @classmethod - def construct(cls, kwargs): - """Handle constructing a session from both old and new arguments. - - Support constructing a session from the old - :py:class:`~keystoneclient.httpclient.HTTPClient` args as well as the - new request-style arguments. - - .. warning:: - - *DEPRECATED as of 1.7.0*: This function is purely for bridging the - gap between older client arguments and the session arguments that - they relate to. It is not intended to be used as a generic Session - Factory. This function may be removed in the 2.0.0 release. - - This function purposefully modifies the input kwargs dictionary so that - the remaining kwargs dict can be reused and passed on to other - functions without session arguments. - - """ - warnings.warn( - 'Session.construct() is deprecated as of the 1.7.0 release in ' - 'favor of using session constructor and may be removed in the ' - '2.0.0 release.', DeprecationWarning) - return cls._construct(kwargs) - - @classmethod - def _construct(cls, kwargs): - params = {} - - for attr in ('verify', 'cacert', 'cert', 'key', 'insecure', - 'timeout', 'session', 'original_ip', 'user_agent'): - try: - params[attr] = kwargs.pop(attr) - except KeyError: # nosec(cjschaef): we are brute force - # identifying possible attributes for kwargs - pass - - return cls._make(**params) - - @classmethod - def _make(cls, insecure=False, verify=None, cacert=None, cert=None, - key=None, **kwargs): - """Create a session with individual certificate parameters. - - Some parameters used to create a session don't lend themselves to be - loaded from config/CLI etc. Create a session by converting those - parameters into session __init__ parameters. - """ - if verify is None: - if insecure: - verify = False - else: - verify = cacert or True - - if cert and key: - warnings.warn( - 'Passing cert and key together is deprecated as of the 1.7.0 ' - 'release in favor of the requests library form of having the ' - 'cert and key as a tuple and may be removed in the 2.0.0 ' - 'release.', DeprecationWarning) - cert = (cert, key) - - return cls(verify=verify, cert=cert, **kwargs) - - def _auth_required(self, auth, msg): - if not auth: - auth = self.auth - - if not auth: - raise exceptions.MissingAuthPlugin(msg) - - return auth - - def get_auth_headers(self, auth=None, **kwargs): - """Return auth headers as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - :returns: Authentication headers or None for failure. - :rtype: dict - """ - msg = _('An auth plugin is required to fetch a token') - auth = self._auth_required(auth, msg) - return auth.get_headers(self, **kwargs) - - @removals.remove(message='Use get_auth_headers instead.', version='1.7.0', - removal_version='2.0.0') - def get_token(self, auth=None): - """Return a token as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - .. warning:: - - This method is deprecated as of the 1.7.0 release in favor of - :meth:`get_auth_headers` and may be removed in the 2.0.0 release. - This method assumes that the only header that is used to - authenticate a message is 'X-Auth-Token' which may not be correct. - - :returns: A valid token. - :rtype: string - """ - return (self.get_auth_headers(auth) or {}).get('X-Auth-Token') - - def get_endpoint(self, auth=None, **kwargs): - """Get an endpoint as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin on - the session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - - :returns: An endpoint if available or None. - :rtype: string - """ - msg = _('An auth plugin is required to determine endpoint URL') - auth = self._auth_required(auth, msg) - return auth.get_endpoint(self, **kwargs) - - def get_auth_connection_params(self, auth=None, **kwargs): - """Return auth connection params as provided by the auth plugin. - - An auth plugin may specify connection parameters to the request like - providing a client certificate for communication. - - We restrict the values that may be returned from this function to - prevent an auth plugin overriding values unrelated to connection - parameters. The values that are currently accepted are: - - - `cert`: a path to a client certificate, or tuple of client - certificate and key pair that are used with this request. - - `verify`: a boolean value to indicate verifying SSL certificates - against the system CAs or a path to a CA file to verify with. - - These values are passed to the requests library and further information - on accepted values may be found there. - - :param auth: The auth plugin to use for tokens. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: if a new token - fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not - available. - :raises keystoneclient.exceptions.UnsupportedParameters: if the plugin - returns a parameter that is not supported by this session. - - :returns: Authentication headers or None for failure. - :rtype: dict - """ - msg = _('An auth plugin is required to fetch connection params') - auth = self._auth_required(auth, msg) - params = auth.get_connection_params(self, **kwargs) - - # NOTE(jamielennox): There needs to be some consensus on what - # parameters are allowed to be modified by the auth plugin here. - # Ideally I think it would be only the send() parts of the request - # flow. For now lets just allow certain elements. - params_copy = params.copy() - - for arg in ('cert', 'verify'): - try: - kwargs[arg] = params_copy.pop(arg) - except KeyError: # nosec(cjschaef): we are brute force - # identifying and removing values in params_copy - pass - - if params_copy: - raise exceptions.UnsupportedParameters(list(params_copy)) - - return params - - def invalidate(self, auth=None): - """Invalidate an authentication plugin. - - :param auth: The auth plugin to invalidate. Overrides the plugin on the - session. (optional) - :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` - - """ - msg = _('An auth plugin is required to validate') - auth = self._auth_required(auth, msg) - return auth.invalidate() - - def get_user_id(self, auth=None): - """Return the authenticated user_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns string: Current user_id or None if not supported by plugin. - """ - msg = _('An auth plugin is required to get user_id') - auth = self._auth_required(auth, msg) - return auth.get_user_id(self) - - def get_project_id(self, auth=None): - """Return the authenticated project_id as provided by the auth plugin. - - :param auth: The auth plugin to use for token. Overrides the plugin - on the session. (optional) - :type auth: keystoneclient.auth.base.BaseAuthPlugin - - :raises keystoneclient.exceptions.AuthorizationFailure: - if a new token fetch fails. - :raises keystoneclient.exceptions.MissingAuthPlugin: - if a plugin is not available. - - :returns string: Current project_id or None if not supported by plugin. - """ - msg = _('An auth plugin is required to get project_id') - auth = self._auth_required(auth, msg) - return auth.get_project_id(self) - - @positional.classmethod() - def get_conf_options(cls, deprecated_opts=None): - """Get oslo_config options that are needed for a :py:class:`.Session`. - - These may be useful without being registered for config file generation - or to manipulate the options before registering them yourself. - - The options that are set are: - :cafile: The certificate authority filename. - :certfile: The client certificate file to present. - :keyfile: The key for the client certificate. - :insecure: Whether to ignore SSL verification. - :timeout: The max time to wait for HTTP connections. - - :param dict deprecated_opts: Deprecated options that should be included - in the definition of new options. This should be a dict from the - name of the new option to a list of oslo.DeprecatedOpts that - correspond to the new option. (optional) - - For example, to support the ``ca_file`` option pointing to the new - ``cafile`` option name:: - - old_opt = oslo_cfg.DeprecatedOpt('ca_file', 'old_group') - deprecated_opts={'cafile': [old_opt]} - - :returns: A list of oslo_config options. - """ - if deprecated_opts is None: - deprecated_opts = {} - - return [cfg.StrOpt('cafile', - deprecated_opts=deprecated_opts.get('cafile'), - help='PEM encoded Certificate Authority to use ' - 'when verifying HTTPs connections.'), - cfg.StrOpt('certfile', - deprecated_opts=deprecated_opts.get('certfile'), - help='PEM encoded client certificate cert file'), - cfg.StrOpt('keyfile', - deprecated_opts=deprecated_opts.get('keyfile'), - help='PEM encoded client certificate key file'), - cfg.BoolOpt('insecure', - default=False, - deprecated_opts=deprecated_opts.get('insecure'), - help='Verify HTTPS connections.'), - cfg.IntOpt('timeout', - deprecated_opts=deprecated_opts.get('timeout'), - help='Timeout value for http requests'), - ] - - @positional.classmethod() - def register_conf_options(cls, conf, group, deprecated_opts=None): - """Register the oslo_config options that are needed for a session. - - The options that are set are: - :cafile: The certificate authority filename. - :certfile: The client certificate file to present. - :keyfile: The key for the client certificate. - :insecure: Whether to ignore SSL verification. - :timeout: The max time to wait for HTTP connections. - - :param oslo_config.Cfg conf: config object to register with. - :param string group: The ini group to register options in. - :param dict deprecated_opts: Deprecated options that should be included - in the definition of new options. This should be a dict from the - name of the new option to a list of oslo.DeprecatedOpts that - correspond to the new option. (optional) - - For example, to support the ``ca_file`` option pointing to the new - ``cafile`` option name:: - - old_opt = oslo_cfg.DeprecatedOpt('ca_file', 'old_group') - deprecated_opts={'cafile': [old_opt]} - - :returns: The list of options that was registered. - """ - opts = cls.get_conf_options(deprecated_opts=deprecated_opts) - conf.register_group(cfg.OptGroup(group)) - conf.register_opts(opts, group=group) - return opts - - @classmethod - def load_from_conf_options(cls, conf, group, **kwargs): - """Create a session object from an oslo_config object. - - The options must have been previously registered with - register_conf_options. - - :param oslo_config.Cfg conf: config object to register with. - :param string group: The ini group to register options in. - :param dict kwargs: Additional parameters to pass to session - construction. - :returns: A new session object. - :rtype: :py:class:`.Session` - """ - c = conf[group] - - kwargs['insecure'] = c.insecure - kwargs['cacert'] = c.cafile - if c.certfile and c.keyfile: - kwargs['cert'] = (c.certfile, c.keyfile) - kwargs['timeout'] = c.timeout - - return cls._make(**kwargs) - - @staticmethod - def register_cli_options(parser): - """Register the argparse arguments that are needed for a session. - - :param argparse.ArgumentParser parser: parser to add to. - """ - parser.add_argument('--insecure', - default=False, - action='store_true', - help='Explicitly allow client to perform ' - '"insecure" TLS (https) requests. The ' - 'server\'s certificate will not be verified ' - 'against any certificate authorities. This ' - 'option should be used with caution.') - - parser.add_argument('--os-cacert', - metavar='', - default=os.environ.get('OS_CACERT'), - help='Specify a CA bundle file to use in ' - 'verifying a TLS (https) server certificate. ' - 'Defaults to env[OS_CACERT].') - - parser.add_argument('--os-cert', - metavar='', - default=os.environ.get('OS_CERT'), - help='Defaults to env[OS_CERT].') - - parser.add_argument('--os-key', - metavar='', - default=os.environ.get('OS_KEY'), - help='Defaults to env[OS_KEY].') - - parser.add_argument('--timeout', - default=600, - type=_positive_non_zero_float, - metavar='', - help='Set request timeout (in seconds).') - - @classmethod - def load_from_cli_options(cls, args, **kwargs): - """Create a :py:class:`.Session` object from CLI arguments. - - The CLI arguments must have been registered with - :py:meth:`.register_cli_options`. - - :param Namespace args: result of parsed arguments. - - :returns: A new session object. - :rtype: :py:class:`.Session` - """ - kwargs['insecure'] = args.insecure - kwargs['cacert'] = args.os_cacert - if args.os_cert and args.os_key: - kwargs['cert'] = (args.os_cert, args.os_key) - kwargs['timeout'] = args.timeout - - return cls._make(**kwargs) - - -class TCPKeepAliveAdapter(requests.adapters.HTTPAdapter): - """The custom adapter used to set TCP Keep-Alive on all connections. - - This Adapter also preserves the default behaviour of Requests which - disables Nagle's Algorithm. See also: - http://blogs.msdn.com/b/windowsazurestorage/archive/2010/06/25/nagle-s-algorithm-is-not-friendly-towards-small-requests.aspx - """ - - def init_poolmanager(self, *args, **kwargs): - if 'socket_options' not in kwargs: - socket_options = [ - # Keep Nagle's algorithm off - (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1), - # Turn on TCP Keep-Alive - (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), - ] - - # Some operating systems (e.g., OSX) do not support setting - # keepidle - if hasattr(socket, 'TCP_KEEPIDLE'): - socket_options += [ - # Wait 60 seconds before sending keep-alive probes - (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60) - ] - - # TODO(claudiub): Windows does not contain the TCP_KEEPCNT and - # TCP_KEEPINTVL socket attributes. Instead, it contains - # SIO_KEEPALIVE_VALS, which can be set via ioctl, which should be - # set once it is available in requests. - # https://msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx - if hasattr(socket, 'TCP_KEEPCNT'): - socket_options += [ - # Set the maximum number of keep-alive probes - (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4) - ] - - if hasattr(socket, 'TCP_KEEPINTVL'): - socket_options += [ - # Send keep-alive probes every 15 seconds - (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15) - ] - - # After waiting 60 seconds, and then sending a probe once every 15 - # seconds 4 times, these options should ensure that a connection - # hands for no longer than 2 minutes before a ConnectionError is - # raised. - - kwargs['socket_options'] = socket_options - super(TCPKeepAliveAdapter, self).init_poolmanager(*args, **kwargs) diff --git a/keystoneclient/tests/__init__.py b/keystoneclient/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/__init__.py b/keystoneclient/tests/functional/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/base.py b/keystoneclient/tests/functional/base.py deleted file mode 100644 index 743cb501..00000000 --- a/keystoneclient/tests/functional/base.py +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from keystoneclient import client -import os_client_config - -IDENTITY_CLIENT = 'identity' -OPENSTACK_CLOUDS = ('functional_admin', 'devstack-admin', 'envvars') - - -def get_client(version): - """Create a keystoneclient instance to run functional tests. - - The client is instantiated via os-client-config either based on a - clouds.yaml config file or from the environment variables. - - First, look for a 'functional_admin' cloud, as this is a cloud that the - user may have defined for functional testing with admin credentials. If - that is not found, check for the 'devstack-admin' cloud. Finally, fall - back to looking for environment variables. - - """ - for cloud in OPENSTACK_CLOUDS: - try: - cloud_config = os_client_config.get_config( - cloud=cloud, identity_api_version=version) - return cloud_config.get_legacy_client(service_key=IDENTITY_CLIENT, - constructor=client.Client) - - except os_client_config.exceptions.OpenStackConfigException: - pass - - raise Exception("Could not find any cloud definition for clouds named" - " functional_admin or devstack-admin. Check your" - " clouds.yaml file or your envvars and try again.") - - -class ClientTestCase(testtools.TestCase): - - def setUp(self): - super(ClientTestCase, self).setUp() - - if not self.auth_ref.project_scoped: - raise Exception("Could not run functional tests, which are " - "run based on the scope provided for " - "authentication. Please provide a project " - "scope information.") - - @property - def client(self): - if not hasattr(self, '_client'): - self._client = get_client(self.version) - - return self._client - - @property - def auth_ref(self): - return self.client.session.auth.get_auth_ref(self.client.session) - - @property - def project_domain_id(self): - return self.auth_ref.project_domain_id - - @property - def project_id(self): - return self.client.session.get_project_id() - - @property - def user_id(self): - return self.client.session.get_user_id() - - -class V3ClientTestCase(ClientTestCase): - version = '3' - - -class V2ClientTestCase(ClientTestCase): - version = '2.0' diff --git a/keystoneclient/tests/functional/hooks/post_test_hook.sh b/keystoneclient/tests/functional/hooks/post_test_hook.sh deleted file mode 100755 index 951c321c..00000000 --- a/keystoneclient/tests/functional/hooks/post_test_hook.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -xe - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script is executed inside post_test_hook function in devstack gate. - -function generate_testr_results { - if [ -f .testrepository/0 ]; then - sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit - sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit - sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html - sudo gzip -9 $BASE/logs/testrepository.subunit - sudo gzip -9 $BASE/logs/testr_results.html - sudo chown jenkins:jenkins $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - fi -} - -export KEYSTONECLIENT_DIR="$BASE/new/python-keystoneclient" - -# Get admin credentials -cd $BASE/new/devstack -source openrc admin admin - -# Go to the keystoneclient dir -cd $KEYSTONECLIENT_DIR - -sudo chown -R jenkins:stack $KEYSTONECLIENT_DIR - -# Run tests -echo "Running keystoneclient functional test suite" -set +e -# Preserve env for OS_ credentials -sudo -E -H -u jenkins tox -efunctional -EXIT_CODE=$? -set -e - -# Collect and parse result -generate_testr_results -exit $EXIT_CODE diff --git a/keystoneclient/tests/functional/test_access.py b/keystoneclient/tests/functional/test_access.py deleted file mode 100644 index 0b202fb6..00000000 --- a/keystoneclient/tests/functional/test_access.py +++ /dev/null @@ -1,50 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -import testtools - -from keystoneclient.auth.identity import v2 -from keystoneclient import session -from tempest.lib import base - - -class TestV2AccessInfo(base.BaseTestCase): - - def setUp(self): - super(TestV2AccessInfo, self).setUp() - - self.session = session.Session() - - @testtools.skip("likely race condition, being skipped") - def test_access_audit_id(self): - unscoped_plugin = v2.Password(auth_url=os.environ.get('OS_AUTH_URL'), - username=os.environ.get('OS_USERNAME'), - password=os.environ.get('OS_PASSWORD')) - - unscoped_auth_ref = unscoped_plugin.get_access(self.session) - - self.assertIsNotNone(unscoped_auth_ref.audit_id) - self.assertIsNone(unscoped_auth_ref.audit_chain_id) - - scoped_plugin = v2.Token(auth_url=os.environ.get('OS_AUTH_URL'), - token=unscoped_auth_ref.auth_token, - tenant_name=os.environ.get('OS_TENANT_NAME')) - - scoped_auth_ref = scoped_plugin.get_access(self.session) - - self.assertIsNotNone(scoped_auth_ref.audit_id) - self.assertIsNotNone(scoped_auth_ref.audit_chain_id) - - self.assertEqual(unscoped_auth_ref.audit_id, - scoped_auth_ref.audit_chain_id) diff --git a/keystoneclient/tests/functional/test_base.py b/keystoneclient/tests/functional/test_base.py deleted file mode 100644 index d5f05166..00000000 --- a/keystoneclient/tests/functional/test_base.py +++ /dev/null @@ -1,28 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import keystoneclient -from keystoneclient.tests.functional import base - - -class V3ClientVersionTestCase(base.V3ClientTestCase): - - def test_version(self): - self.assertIsInstance(self.client, - keystoneclient.v3.client.Client) - - -class V2ClientVersionTestCase(base.V2ClientTestCase): - - def test_version(self): - self.assertIsInstance(self.client, - keystoneclient.v2_0.client.Client) diff --git a/keystoneclient/tests/functional/v2_0/__init__.py b/keystoneclient/tests/functional/v2_0/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/v3/__init__.py b/keystoneclient/tests/functional/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/functional/v3/client_fixtures.py b/keystoneclient/tests/functional/v3/client_fixtures.py deleted file mode 100644 index dd7209a6..00000000 --- a/keystoneclient/tests/functional/v3/client_fixtures.py +++ /dev/null @@ -1,250 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -import uuid - - -RESOURCE_NAME_PREFIX = 'keystoneclient-functional-' - - -class Base(fixtures.Fixture): - - def __init__(self, client, domain_id=None): - super(Base, self).__init__() - - self.client = client - self.domain_id = domain_id - self.ref = None - self.entity = None - - def __getattr__(self, name): - """Return the attribute from the represented entity.""" - return getattr(self.entity, name) - - -class User(Base): - - def setUp(self): - super(User, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.domain_id} - self.entity = self.client.users.create(**self.ref) - self.addCleanup(self.client.users.delete, self.entity) - - -class Group(Base): - - def setUp(self): - super(Group, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.domain_id} - self.entity = self.client.groups.create(**self.ref) - self.addCleanup(self.client.groups.delete, self.entity) - - -class Domain(Base): - - def setUp(self): - super(Domain, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'description': uuid.uuid4().hex, - 'enabled': True} - self.entity = self.client.domains.create(**self.ref) - - # Only disabled domains can be deleted - self.addCleanup(self.client.domains.delete, self.entity) - self.addCleanup(self.client.domains.update, self.entity, enabled=False) - - -class Project(Base): - - def __init__(self, client, domain_id=None, parent=None): - super(Project, self).__init__(client, domain_id) - self.parent = parent - - def setUp(self): - super(Project, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.domain_id, - 'enabled': True, - 'parent': self.parent} - self.entity = self.client.projects.create(**self.ref) - self.addCleanup(self.client.projects.delete, self.entity) - - -class Role(Base): - - def __init__(self, client, name=None, domain=None): - super(Role, self).__init__(client) - self.name = name or RESOURCE_NAME_PREFIX + uuid.uuid4().hex - self.domain = domain - - def setUp(self): - super(Role, self).setUp() - - self.ref = {'name': self.name, - 'domain': self.domain} - self.entity = self.client.roles.create(**self.ref) - self.addCleanup(self.client.roles.delete, self.entity) - - -class InferenceRule(Base): - - def __init__(self, client, prior_role, implied_role): - super(InferenceRule, self).__init__(client) - self.prior_role = prior_role - self.implied_role = implied_role - - def setUp(self): - super(InferenceRule, self).setUp() - - self.ref = {'prior_role': self.prior_role, - 'implied_role': self.implied_role} - self.entity = self.client.inference_rules.create(**self.ref) - self.addCleanup(self.client.inference_rules.delete, self.prior_role, - self.implied_role) - - -class Service(Base): - - def setUp(self): - super(Service, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'type': uuid.uuid4().hex, - 'enabled': True, - 'description': uuid.uuid4().hex} - self.entity = self.client.services.create(**self.ref) - self.addCleanup(self.client.services.delete, self.entity) - - -class Policy(Base): - - def setUp(self): - super(Policy, self).setUp() - - self.ref = {'blob': uuid.uuid4().hex, - 'type': uuid.uuid4().hex} - self.entity = self.client.policies.create(**self.ref) - self.addCleanup(self.client.policies.delete, self.entity) - - -class Region(Base): - - def __init__(self, client, parent_region=None): - super(Region, self).__init__(client) - self.parent_region = parent_region - - def setUp(self): - super(Region, self).setUp() - - self.ref = {'description': uuid.uuid4().hex, - 'parent_region': self.parent_region} - self.entity = self.client.regions.create(**self.ref) - self.addCleanup(self.client.regions.delete, self.entity) - - -class Endpoint(Base): - - def __init__(self, client, service, interface, region=None): - super(Endpoint, self).__init__(client) - self.service = service - self.interface = interface - self.region = region - - def setUp(self): - super(Endpoint, self).setUp() - - self.ref = {'service': self.service, - 'url': 'http://' + uuid.uuid4().hex, - 'enabled': True, - 'interface': self.interface, - 'region': self.region} - self.entity = self.client.endpoints.create(**self.ref) - self.addCleanup(self.client.endpoints.delete, self.entity) - - -class EndpointGroup(Base): - - def setUp(self): - super(EndpointGroup, self).setUp() - - self.ref = {'name': RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'filters': {'interface': 'public'}, - 'description': uuid.uuid4().hex} - self.entity = self.client.endpoint_groups.create(**self.ref) - self.addCleanup(self.client.endpoint_groups.delete, self.entity) - - -class Credential(Base): - - def __init__(self, client, user, type, project=None): - super(Credential, self).__init__(client) - self.user = user - self.type = type - self.project = project - - if type == 'ec2': - self.blob = ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}") - else: - self.blob = uuid.uuid4().hex - - def setUp(self): - super(Credential, self).setUp() - - self.ref = {'user': self.user, - 'type': self.type, - 'blob': self.blob, - 'project': self.project} - self.entity = self.client.credentials.create(**self.ref) - self.addCleanup(self.client.credentials.delete, self.entity) - - -class EC2(Base): - - def __init__(self, client, user_id, project_id): - super(EC2, self).__init__(client) - self.user_id = user_id - self.project_id = project_id - - def setUp(self): - super(EC2, self).setUp() - - self.ref = {'user_id': self.user_id, - 'project_id': self.project_id} - self.entity = self.client.ec2.create(**self.ref) - self.addCleanup(self.client.ec2.delete, - self.user_id, - self.entity.access) - - -class DomainConfig(Base): - - def __init__(self, client, domain_id): - super(DomainConfig, self).__init__(client, domain_id=domain_id) - self.domain_id = domain_id - - def setUp(self): - super(DomainConfig, self).setUp() - - self.ref = {'identity': {'driver': uuid.uuid4().hex}, - 'ldap': {'url': uuid.uuid4().hex}} - self.entity = self.client.domain_configs.create( - self.domain_id, self.ref) - self.addCleanup(self.client.domain_configs.delete, - self.domain_id) diff --git a/keystoneclient/tests/functional/v3/test_credentials.py b/keystoneclient/tests/functional/v3/test_credentials.py deleted file mode 100644 index a5d00b1c..00000000 --- a/keystoneclient/tests/functional/v3/test_credentials.py +++ /dev/null @@ -1,194 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class CredentialsTestCase(base.V3ClientTestCase): - - def setUp(self): - super(CredentialsTestCase, self).setUp() - self.test_domain = fixtures.Domain(self.client) - self.useFixture(self.test_domain) - - def check_credential(self, credential, credential_ref=None): - self.assertIsNotNone(credential.id) - self.assertIn('self', credential.links) - self.assertIn('/credentials/' + credential.id, - credential.links['self']) - - if credential_ref: - self.assertEqual(credential_ref['user'], credential.user_id) - self.assertEqual(credential_ref['type'], credential.type) - self.assertEqual(credential_ref['blob'], credential.blob) - - # There is no guarantee below attributes are present in credential - if credential_ref['type'] == 'ec2' or hasattr(credential_ref, - 'project'): - self.assertEqual(credential_ref['project'], - credential.project_id) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(credential.user_id) - self.assertIsNotNone(credential.type) - self.assertIsNotNone(credential.blob) - if credential.type == 'ec2': - self.assertIsNotNone(credential.project_id) - - def test_create_credential_of_cert_type(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - credential_ref = {'user': user.id, - 'type': 'cert', - 'blob': uuid.uuid4().hex} - credential = self.client.credentials.create(**credential_ref) - - self.addCleanup(self.client.credentials.delete, credential) - self.check_credential(credential, credential_ref) - - def test_create_credential_of_ec2_type(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - # project is mandatory attribute if the credential type is ec2 - credential_ref = {'user': user.id, - 'type': 'ec2', - 'blob': ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}")} - self.assertRaises(http.BadRequest, - self.client.credentials.create, - **credential_ref) - - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - credential_ref = {'user': user.id, - 'type': 'ec2', - 'blob': ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}"), - 'project': project.id} - credential = self.client.credentials.create(**credential_ref) - - self.addCleanup(self.client.credentials.delete, credential) - self.check_credential(credential, credential_ref) - - def test_create_credential_of_totp_type(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - credential_ref = {'user': user.id, - 'type': 'totp', - 'blob': uuid.uuid4().hex} - credential = self.client.credentials.create(**credential_ref) - - self.addCleanup(self.client.credentials.delete, credential) - self.check_credential(credential, credential_ref) - - def test_get_credential(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - for credential_type in ['cert', 'ec2', 'totp']: - credential = fixtures.Credential(self.client, user=user.id, - type=credential_type, - project=project.id) - self.useFixture(credential) - - credential_ret = self.client.credentials.get(credential.id) - self.check_credential(credential_ret, credential.ref) - - def test_list_credentials(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - cert_credential = fixtures.Credential(self.client, user=user.id, - type='cert') - self.useFixture(cert_credential) - - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - ec2_credential = fixtures.Credential(self.client, user=user.id, - type='ec2', project=project.id) - self.useFixture(ec2_credential) - - totp_credential = fixtures.Credential(self.client, user=user.id, - type='totp') - self.useFixture(totp_credential) - - credentials = self.client.credentials.list() - - # All credentials are valid - for credential in credentials: - self.check_credential(credential) - - self.assertIn(cert_credential.entity, credentials) - self.assertIn(ec2_credential.entity, credentials) - self.assertIn(totp_credential.entity, credentials) - - def test_update_credential(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - - new_user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(new_user) - new_project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(new_project) - - credential = fixtures.Credential(self.client, user=user.id, - type='cert') - self.useFixture(credential) - - new_type = 'ec2' - new_blob = ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}") - - credential_ret = self.client.credentials.update(credential.id, - user=new_user.id, - type=new_type, - blob=new_blob, - project=new_project.id) - - credential.ref.update({'user': new_user.id, 'type': new_type, - 'blob': new_blob, 'project': new_project.id}) - self.check_credential(credential_ret, credential.ref) - - def test_delete_credential(self): - user = fixtures.User(self.client, self.test_domain.id) - self.useFixture(user) - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - for credential_type in ['cert', 'ec2', 'totp']: - - if credential_type == 'ec2': - blob_value = ("{\"access\":\"" + uuid.uuid4().hex + - "\",\"secret\":\"secretKey\"}") - else: - blob_value = uuid.uuid4().hex - - credential = self.client.credentials.create(user=user.id, - type=credential_type, - blob=blob_value, - project=project.id) - self.client.credentials.delete(credential.id) - self.assertRaises(http.NotFound, - self.client.credentials.get, - credential.id) diff --git a/keystoneclient/tests/functional/v3/test_domain_configs.py b/keystoneclient/tests/functional/v3/test_domain_configs.py deleted file mode 100644 index f3ca71a2..00000000 --- a/keystoneclient/tests/functional/v3/test_domain_configs.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class DomainConfigsTestCase(base.V3ClientTestCase): - - def setUp(self): - super(DomainConfigsTestCase, self).setUp() - self.test_domain = fixtures.Domain(self.client) - self.useFixture(self.test_domain) - - def check_domain_config(self, config, config_ref): - for attr in config_ref: - self.assertEqual( - getattr(config, attr), - config_ref[attr], - 'Expected different %s' % attr) - - def _new_ref(self): - return {'identity': {'driver': uuid.uuid4().hex}, - 'ldap': {'url': uuid.uuid4().hex}} - - def test_create_domain_config(self): - config_ref = self._new_ref() - config = self.client.domain_configs.create( - self.test_domain.id, config_ref) - self.addCleanup( - self.client.domain_configs.delete, self.test_domain.id) - self.check_domain_config(config, config_ref) - - def test_create_invalid_domain_config(self): - invalid_groups_ref = { - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}, - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.create, - self.test_domain.id, - invalid_groups_ref) - - invalid_options_ref = { - 'identity': {uuid.uuid4().hex: uuid.uuid4().hex}, - 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.create, - self.test_domain.id, - invalid_options_ref) - - def test_get_domain_config(self): - config = fixtures.DomainConfig(self.client, self.test_domain.id) - self.useFixture(config) - - config_ret = self.client.domain_configs.get(self.test_domain.id) - self.check_domain_config(config_ret, config.ref) - - def test_update_domain_config(self): - config = fixtures.DomainConfig(self.client, self.test_domain.id) - self.useFixture(config) - - update_config_ref = self._new_ref() - config_ret = self.client.domain_configs.update( - self.test_domain.id, update_config_ref) - self.check_domain_config(config_ret, update_config_ref) - - def test_update_invalid_domain_config(self): - config = fixtures.DomainConfig(self.client, self.test_domain.id) - self.useFixture(config) - - invalid_groups_ref = { - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}, - uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.update, - self.test_domain.id, - invalid_groups_ref) - - invalid_options_ref = { - 'identity': {uuid.uuid4().hex: uuid.uuid4().hex}, - 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}} - self.assertRaises(http.Forbidden, - self.client.domain_configs.update, - self.test_domain.id, - invalid_options_ref) - - def test_domain_config_delete(self): - config_ref = self._new_ref() - self.client.domain_configs.create(self.test_domain.id, config_ref) - - self.client.domain_configs.delete(self.test_domain.id) - self.assertRaises(http.NotFound, - self.client.domain_configs.get, - self.project_domain_id) diff --git a/keystoneclient/tests/functional/v3/test_domains.py b/keystoneclient/tests/functional/v3/test_domains.py deleted file mode 100644 index cdfbdd74..00000000 --- a/keystoneclient/tests/functional/v3/test_domains.py +++ /dev/null @@ -1,97 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class DomainsTestCase(base.V3ClientTestCase): - - def check_domain(self, domain, domain_ref=None): - self.assertIsNotNone(domain.id) - self.assertIn('self', domain.links) - self.assertIn('/domains/' + domain.id, domain.links['self']) - - if domain_ref: - self.assertEqual(domain_ref['name'], domain.name) - self.assertEqual(domain_ref['enabled'], domain.enabled) - - # There is no guarantee description is present in domain - if hasattr(domain_ref, 'description'): - self.assertEqual(domain_ref['description'], domain.description) - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(domain.name) - self.assertIsNotNone(domain.enabled) - - def test_create_domain(self): - domain_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'description': uuid.uuid4().hex, - 'enabled': True} - domain = self.client.domains.create(**domain_ref) - self.check_domain(domain, domain_ref) - - # Only disabled domains can be deleted - self.addCleanup(self.client.domains.delete, domain) - self.addCleanup(self.client.domains.update, domain, enabled=False) - - def test_get_domain(self): - domain_id = self.project_domain_id - domain_ret = self.client.domains.get(domain_id) - self.check_domain(domain_ret) - - def test_list_domains(self): - domain_one = fixtures.Domain(self.client) - self.useFixture(domain_one) - - domain_two = fixtures.Domain(self.client) - self.useFixture(domain_two) - - domains = self.client.domains.list() - - # All domains are valid - for domain in domains: - self.check_domain(domain) - - self.assertIn(domain_one.entity, domains) - self.assertIn(domain_two.entity, domains) - - def test_update_domain(self): - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - new_description = uuid.uuid4().hex - domain_ret = self.client.domains.update(domain.id, - description=new_description) - - domain.ref.update({'description': new_description}) - self.check_domain(domain_ret, domain.ref) - - def test_delete_domain(self): - domain = self.client.domains.create(name=uuid.uuid4().hex, - description=uuid.uuid4().hex, - enabled=True) - - # Only disabled domains can be deleted - self.assertRaises(http.Forbidden, - self.client.domains.delete, - domain.id) - - self.client.domains.update(domain, enabled=False) - self.client.domains.delete(domain.id) - self.assertRaises(http.NotFound, - self.client.domains.get, - domain.id) diff --git a/keystoneclient/tests/functional/v3/test_ec2.py b/keystoneclient/tests/functional/v3/test_ec2.py deleted file mode 100644 index 09703b0d..00000000 --- a/keystoneclient/tests/functional/v3/test_ec2.py +++ /dev/null @@ -1,92 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class EC2TestCase(base.V3ClientTestCase): - - def check_ec2(self, ec2, ec2_ref=None): - self.assertIn('self', ec2.links) - self.assertIn('/users/%s/credentials/OS-EC2/%s' - % (ec2.user_id, ec2.access), ec2.links['self']) - - if ec2_ref: - self.assertEqual(ec2_ref['user_id'], ec2.user_id) - self.assertEqual(ec2_ref['project_id'], ec2.tenant_id) - - else: - self.assertIsNotNone(ec2.user_id) - self.assertIsNotNone(ec2.tenant_id) - - def test_create_ec2(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - ec2_ref = {'user_id': user.id, - 'project_id': project.id} - ec2 = self.client.ec2.create(**ec2_ref) - - self.addCleanup(self.client.ec2.delete, user.id, ec2.access) - self.check_ec2(ec2, ec2_ref) - - def test_get_ec2(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - ec2 = fixtures.EC2(self.client, user_id=user.id, project_id=project.id) - self.useFixture(ec2) - - ec2_ret = self.client.ec2.get(user.id, ec2.access) - self.check_ec2(ec2_ret, ec2.ref) - - def test_list_ec2(self): - user_one = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_one) - ec2_one = fixtures.EC2(self.client, user_id=user_one.id, - project_id=self.project_domain_id) - self.useFixture(ec2_one) - - user_two = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_two) - ec2_two = fixtures.EC2(self.client, user_id=user_two.id, - project_id=self.project_domain_id) - self.useFixture(ec2_two) - - ec2_list = self.client.ec2.list(user_one.id) - - # All ec2 are valid - for ec2 in ec2_list: - self.check_ec2(ec2) - - self.assertIn(ec2_one.entity, ec2_list) - self.assertNotIn(ec2_two.entity, ec2_list) - - def test_delete_ec2(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - ec2 = self.client.ec2.create(user.id, project.id) - - self.client.ec2.delete(user.id, ec2.access) - self.assertRaises(http.NotFound, - self.client.ec2.get, - user.id, ec2.access) diff --git a/keystoneclient/tests/functional/v3/test_endpoint_filters.py b/keystoneclient/tests/functional/v3/test_endpoint_filters.py deleted file mode 100644 index d8956bed..00000000 --- a/keystoneclient/tests/functional/v3/test_endpoint_filters.py +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures -from keystoneclient.tests.functional.v3 import test_endpoint_groups -from keystoneclient.tests.functional.v3 import test_projects - - -class EndpointFiltersTestCase(base.V3ClientTestCase, - test_endpoint_groups.EndpointGroupsTestMixin, - test_projects.ProjectsTestMixin): - - def setUp(self): - super(EndpointFiltersTestCase, self).setUp() - - self.project = fixtures.Project(self.client) - self.endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(self.project) - self.useFixture(self.endpoint_group) - - self.client.endpoint_filter.add_endpoint_group_to_project( - self.endpoint_group, self.project) - - def test_add_endpoint_group_to_project(self): - project = fixtures.Project(self.client) - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(project) - self.useFixture(endpoint_group) - - self.client.endpoint_filter.add_endpoint_group_to_project( - endpoint_group, project) - self.client.endpoint_filter.check_endpoint_group_in_project( - endpoint_group, project) - - def test_delete_endpoint_group_from_project(self): - self.client.endpoint_filter.delete_endpoint_group_from_project( - self.endpoint_group, self.project) - self.assertRaises( - http.NotFound, - self.client.endpoint_filter.check_endpoint_group_in_project, - self.endpoint_group, self.project) - - def test_list_endpoint_groups_for_project(self): - endpoint_group_two = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group_two) - self.client.endpoint_filter.add_endpoint_group_to_project( - endpoint_group_two, self.project) - - endpoint_groups = ( - self.client.endpoint_filter.list_endpoint_groups_for_project( - self.project - ) - ) - - for endpoint_group in endpoint_groups: - self.check_endpoint_group(endpoint_group) - - self.assertIn(self.endpoint_group.entity, endpoint_groups) - self.assertIn(endpoint_group_two.entity, endpoint_groups) - - def test_list_projects_for_endpoint_group(self): - project_two = fixtures.Project(self.client) - self.useFixture(project_two) - self.client.endpoint_filter.add_endpoint_group_to_project( - self.endpoint_group, project_two) - - f = self.client.endpoint_filter.list_projects_for_endpoint_group - projects = f(self.endpoint_group) - - for project in projects: - self.check_project(project) - - self.assertIn(self.project.entity, projects) - self.assertIn(project_two.entity, projects) diff --git a/keystoneclient/tests/functional/v3/test_endpoint_groups.py b/keystoneclient/tests/functional/v3/test_endpoint_groups.py deleted file mode 100644 index 52fcf724..00000000 --- a/keystoneclient/tests/functional/v3/test_endpoint_groups.py +++ /dev/null @@ -1,123 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class EndpointGroupsTestMixin(object): - - def check_endpoint_group(self, endpoint_group, endpoint_group_ref=None): - self.assertIsNotNone(endpoint_group.id) - self.assertIn('self', endpoint_group.links) - self.assertIn('/endpoint_groups/' + endpoint_group.id, - endpoint_group.links['self']) - - if endpoint_group_ref: - self.assertEqual(endpoint_group_ref['name'], endpoint_group.name) - self.assertEqual(endpoint_group_ref['filters'], - endpoint_group.filters) - - # There is no guarantee description is present in endpoint groups - if hasattr(endpoint_group_ref, 'description'): - self.assertEqual(endpoint_group_ref['description'], - endpoint_group.description) - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(endpoint_group.name) - self.assertIsNotNone(endpoint_group.filters) - - -class EndpointGroupsTestCase(base.V3ClientTestCase, EndpointGroupsTestMixin): - - def test_create_endpoint_group(self): - endpoint_group_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'filters': {'interface': 'internal'}, - 'description': uuid.uuid4().hex} - endpoint_group = self.client.endpoint_groups.create( - **endpoint_group_ref) - - self.addCleanup(self.client.endpoint_groups.delete, endpoint_group) - self.check_endpoint_group(endpoint_group, endpoint_group_ref) - - def test_get_endpoint_group(self): - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group) - - endpoint_ret = self.client.endpoint_groups.get(endpoint_group.id) - self.check_endpoint_group(endpoint_ret, endpoint_group.ref) - - self.assertRaises(http.NotFound, - self.client.endpoint_groups.get, - uuid.uuid4().hex) - - def test_check_endpoint_group(self): - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group) - - self.client.endpoint_groups.check(endpoint_group.id) - self.assertRaises(http.NotFound, - self.client.endpoint_groups.check, - uuid.uuid4().hex) - - def test_list_endpoint_groups(self): - endpoint_group_one = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group_one) - - endpoint_group_two = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group_two) - - endpoint_groups = self.client.endpoint_groups.list() - - # All endpoints are valid - for endpoint_group in endpoint_groups: - self.check_endpoint_group(endpoint_group) - - self.assertIn(endpoint_group_one.entity, endpoint_groups) - self.assertIn(endpoint_group_two.entity, endpoint_groups) - - def test_update_endpoint_group(self): - endpoint_group = fixtures.EndpointGroup(self.client) - self.useFixture(endpoint_group) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_filters = {'interface': 'public'} - new_description = uuid.uuid4().hex - - endpoint_group_ret = self.client.endpoint_groups.update( - endpoint_group, - name=new_name, - filters=new_filters, - description=new_description) - - endpoint_group.ref.update({'name': new_name, 'filters': new_filters, - 'description': new_description}) - self.check_endpoint_group(endpoint_group_ret, endpoint_group.ref) - - def test_delete_endpoint_group(self): - endpoint_group = self.client.endpoint_groups.create( - name=fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - filters={'interface': 'admin'}, - description=uuid.uuid4().hex) - - self.client.endpoint_groups.delete(endpoint_group.id) - self.assertRaises(http.NotFound, - self.client.endpoint_groups.check, - endpoint_group.id) - self.assertRaises(http.NotFound, - self.client.endpoint_groups.get, - endpoint_group.id) diff --git a/keystoneclient/tests/functional/v3/test_endpoints.py b/keystoneclient/tests/functional/v3/test_endpoints.py deleted file mode 100644 index c8379706..00000000 --- a/keystoneclient/tests/functional/v3/test_endpoints.py +++ /dev/null @@ -1,141 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class EndpointsTestCase(base.V3ClientTestCase): - - def check_endpoint(self, endpoint, endpoint_ref=None): - self.assertIsNotNone(endpoint.id) - self.assertIn('self', endpoint.links) - self.assertIn('/endpoints/' + endpoint.id, endpoint.links['self']) - - if endpoint_ref: - self.assertEqual(endpoint_ref['service'], endpoint.service_id) - self.assertEqual(endpoint_ref['url'], endpoint.url) - self.assertEqual(endpoint_ref['interface'], endpoint.interface) - self.assertEqual(endpoint_ref['enabled'], endpoint.enabled) - - # There is no guarantee below attributes are present in endpoint - if hasattr(endpoint_ref, 'region'): - self.assertEqual(endpoint_ref['region'], endpoint.region) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(endpoint.service_id) - self.assertIsNotNone(endpoint.url) - self.assertIsNotNone(endpoint.interface) - self.assertIsNotNone(endpoint.enabled) - - def test_create_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - endpoint_ref = {'service': service.id, - 'url': 'http://' + uuid.uuid4().hex, - 'enabled': True, - 'interface': 'public'} - endpoint = self.client.endpoints.create(**endpoint_ref) - - self.addCleanup(self.client.endpoints.delete, endpoint) - self.check_endpoint(endpoint, endpoint_ref) - - def test_get_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - interfaces = ['public', 'admin', 'internal'] - for interface in interfaces: - endpoint = fixtures.Endpoint(self.client, service.id, interface) - self.useFixture(endpoint) - endpoint_ret = self.client.endpoints.get(endpoint.id) - # All endpoints are valid - self.check_endpoint(endpoint_ret, endpoint.ref) - - def test_list_endpoints(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - region = fixtures.Region(self.client) - self.useFixture(region) - - endpoint_one = fixtures.Endpoint(self.client, service.id, 'public', - region=region.id) - self.useFixture(endpoint_one) - - endpoint_two = fixtures.Endpoint(self.client, service.id, 'admin', - region=region.id) - self.useFixture(endpoint_two) - - endpoint_three = fixtures.Endpoint(self.client, service.id, 'internal', - region=region.id) - self.useFixture(endpoint_three) - - endpoints = self.client.endpoints.list() - - # All endpoints are valid - for endpoint in endpoints: - self.check_endpoint(endpoint) - - self.assertIn(endpoint_one.entity, endpoints) - self.assertIn(endpoint_two.entity, endpoints) - self.assertIn(endpoint_three.entity, endpoints) - - def test_update_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - new_service = fixtures.Service(self.client) - self.useFixture(new_service) - - new_region = fixtures.Region(self.client) - self.useFixture(new_region) - - endpoint = fixtures.Endpoint(self.client, service.id, 'public') - self.useFixture(endpoint) - - new_url = 'http://' + uuid.uuid4().hex - new_interface = 'internal' - new_enabled = False - - endpoint_ret = self.client.endpoints.update(endpoint.id, - service=new_service.id, - url=new_url, - interface=new_interface, - enabled=new_enabled, - region=new_region.id) - - endpoint.ref.update({'service': new_service.id, 'url': new_url, - 'interface': new_interface, - 'enabled': new_enabled, - 'region': new_region.entity}) - self.check_endpoint(endpoint_ret, endpoint.ref) - - def test_delete_endpoint(self): - service = fixtures.Service(self.client) - self.useFixture(service) - endpoint = self.client.endpoints.create(service=service.id, - url='http://' + - uuid.uuid4().hex, - enabled=True, - interface='public') - - self.client.endpoints.delete(endpoint.id) - self.assertRaises(http.NotFound, - self.client.endpoints.get, - endpoint.id) diff --git a/keystoneclient/tests/functional/v3/test_federation.py b/keystoneclient/tests/functional/v3/test_federation.py deleted file mode 100644 index da312662..00000000 --- a/keystoneclient/tests/functional/v3/test_federation.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base - - -class TestIdentityProviders(base.V3ClientTestCase): - - def test_idp_create(self): - idp_id = uuid.uuid4().hex - # Create an identity provider just passing an ID - idp = self.client.federation.identity_providers.create(id=idp_id) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - self.assertEqual(idp_id, idp.id) - self.assertEqual([], idp.remote_ids) - self.assertFalse(idp.enabled) - - def test_idp_create_enabled_true(self): - # Create an enabled identity provider - idp_id = uuid.uuid4().hex - idp = self.client.federation.identity_providers.create( - id=idp_id, enabled=True) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - self.assertEqual(idp_id, idp.id) - self.assertEqual([], idp.remote_ids) - self.assertTrue(idp.enabled) - - def test_idp_create_with_remote_ids(self): - # Create an enabled identity provider with remote IDs - idp_id = uuid.uuid4().hex - remote_ids = [uuid.uuid4().hex, uuid.uuid4().hex] - idp = self.client.federation.identity_providers.create( - id=idp_id, enabled=True, remote_ids=remote_ids) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - self.assertEqual(idp_id, idp.id) - self.assertIn(remote_ids[0], idp.remote_ids) - self.assertIn(remote_ids[1], idp.remote_ids) - self.assertTrue(idp.enabled) - - def test_idp_list(self): - idp_ids = [] - for _ in range(3): - idp_id = uuid.uuid4().hex - self.client.federation.identity_providers.create(id=idp_id) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - idp_ids.append(idp_id) - - idp_list = self.client.federation.identity_providers.list() - fetched_ids = [fetched_idp.id for fetched_idp in idp_list] - for idp_id in idp_ids: - self.assertIn(idp_id, fetched_ids) - - def test_idp_get(self): - idp_id = uuid.uuid4().hex - remote_ids = [uuid.uuid4().hex, uuid.uuid4().hex] - idp_create = self.client.federation.identity_providers.create( - id=idp_id, enabled=True, remote_ids=remote_ids) - self.addCleanup( - self.client.federation.identity_providers.delete, idp_id) - - idp_get = self.client.federation.identity_providers.get(idp_id) - self.assertEqual(idp_create.id, idp_get.id) - self.assertEqual(idp_create.enabled, idp_get.enabled) - self.assertIn(idp_create.remote_ids[0], idp_get.remote_ids) - self.assertIn(idp_create.remote_ids[1], idp_get.remote_ids) - - def test_idp_delete(self): - idp_id = uuid.uuid4().hex - self.client.federation.identity_providers.create(id=idp_id) - - # Get should not raise an error - self.client.federation.identity_providers.get(idp_id) - - # Delete it - self.client.federation.identity_providers.delete(idp_id) - - # Now get should raise an error - self.assertRaises( - http.NotFound, - self.client.federation.identity_providers.get, - idp_id) - - # Should not be present in the identity provider list - idp_list = self.client.federation.identity_providers.list() - fetched_ids = [fetched_idp.id for fetched_idp in idp_list] - self.assertNotIn(idp_id, fetched_ids) diff --git a/keystoneclient/tests/functional/v3/test_groups.py b/keystoneclient/tests/functional/v3/test_groups.py deleted file mode 100644 index 5e818ab1..00000000 --- a/keystoneclient/tests/functional/v3/test_groups.py +++ /dev/null @@ -1,94 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class GroupsTestCase(base.V3ClientTestCase): - - def check_group(self, group, group_ref=None): - self.assertIsNotNone(group.id) - self.assertIn('self', group.links) - self.assertIn('/groups/' + group.id, group.links['self']) - - if group_ref: - self.assertEqual(group_ref['name'], group.name) - self.assertEqual(group_ref['domain'], group.domain_id) - - # There is no guarantee description is present in group - if hasattr(group_ref, 'description'): - self.assertEqual(group_ref['description'], group.description) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(group.name) - self.assertIsNotNone(group.domain_id) - - def test_create_group(self): - group_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id, - 'description': uuid.uuid4().hex} - - group = self.client.groups.create(**group_ref) - self.addCleanup(self.client.groups.delete, group) - self.check_group(group, group_ref) - - def test_get_group(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - group_ret = self.client.groups.get(group.id) - self.check_group(group_ret, group.ref) - - def test_list_groups(self): - group_one = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group_one) - - group_two = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group_two) - - groups = self.client.groups.list() - - # All groups are valid - for group in groups: - self.check_group(group) - - self.assertIn(group_one.entity, groups) - self.assertIn(group_two.entity, groups) - - def test_update_group(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_description = uuid.uuid4().hex - - group_ret = self.client.groups.update(group.id, - name=new_name, - description=new_description) - - group.ref.update({'name': new_name, 'description': new_description}) - self.check_group(group_ret, group.ref) - - def test_delete_group(self): - group = self.client.groups.create(name=uuid.uuid4().hex, - domain=self.project_domain_id) - - self.client.groups.delete(group.id) - self.assertRaises(http.NotFound, - self.client.groups.get, - group.id) diff --git a/keystoneclient/tests/functional/v3/test_implied_roles.py b/keystoneclient/tests/functional/v3/test_implied_roles.py deleted file mode 100644 index 0d5dbc5f..00000000 --- a/keystoneclient/tests/functional/v3/test_implied_roles.py +++ /dev/null @@ -1,74 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -role_defs = ["test_admin", - "test_id_manager", - "test_resource_manager", - "test_role_manager", - "test_assignment_manager", - "test_domain_manager", - "test_project_manager", - "test_catalog_manager", - "test_policy_manager", - "test_observer", - "test_domain_tech_lead", - "test_project_observer", - "test_member"] - -inference_rules = {"test_admin": "test_id_manager", - "test_admin": "test_resource_manager", - "test_admin": "test_role_manager", - "test_admin": "test_catalog_manager", - "test_admin": "test_policy_manager", - "test_id_manager": "test_project_observer", - "test_resource_manager": "test_project_observer", - "test_role_manager": "test_project_observer", - "test_catalog_manager": "test_project_observer", - "test_policy_manager": "test_project_observer", - "test_project_observer": "test_observer", - "test_member": "test_observer"} - - -class TestImpliedRoles(base.V3ClientTestCase): - - def setUp(self): - super(TestImpliedRoles, self).setUp() - - def test_implied_roles(self): - initial_rule_count = ( - len(self.client.inference_rules.list_inference_roles())) - - self.create_roles() - self.create_rules() - rule_count = len(self.client.inference_rules.list_inference_roles()) - self.assertEqual(initial_rule_count + len(inference_rules), - rule_count) - - def role_dict(self): - roles = {role.name: role.id for role in self.client.roles.list()} - return roles - - def create_roles(self): - for role_def in role_defs: - role = fixtures.Role(self.client, name=role_def) - self.useFixture(role) - - def create_rules(self): - roles = self.role_dict() - for prior, implied in inference_rules.items(): - rule = fixtures.InferenceRule(self.client, roles[prior], - roles[implied]) - self.useFixture(rule) diff --git a/keystoneclient/tests/functional/v3/test_policies.py b/keystoneclient/tests/functional/v3/test_policies.py deleted file mode 100644 index 6ad0aae7..00000000 --- a/keystoneclient/tests/functional/v3/test_policies.py +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class PoliciesTestCase(base.V3ClientTestCase): - - def check_policy(self, policy, policy_ref=None): - self.assertIsNotNone(policy.id) - self.assertIn('self', policy.links) - self.assertIn('/policies/' + policy.id, policy.links['self']) - - if policy_ref: - self.assertEqual(policy_ref['blob'], policy.blob) - self.assertEqual(policy_ref['type'], policy.type) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(policy.blob) - self.assertIsNotNone(policy.type) - - def test_create_policy(self): - policy_ref = {'blob': uuid.uuid4().hex, - 'type': uuid.uuid4().hex} - - policy = self.client.policies.create(**policy_ref) - self.addCleanup(self.client.policies.delete, policy) - self.check_policy(policy, policy_ref) - - def test_get_policy(self): - policy = fixtures.Policy(self.client) - self.useFixture(policy) - - policy_ret = self.client.policies.get(policy.id) - self.check_policy(policy_ret, policy.ref) - - def test_list_policies(self): - policy_one = fixtures.Policy(self.client) - self.useFixture(policy_one) - - policy_two = fixtures.Policy(self.client) - self.useFixture(policy_two) - - policies = self.client.policies.list() - - # All policies are valid - for policy in policies: - self.check_policy(policy) - - self.assertIn(policy_one.entity, policies) - self.assertIn(policy_two.entity, policies) - - def test_update_policy(self): - policy = fixtures.Policy(self.client) - self.useFixture(policy) - - new_blob = uuid.uuid4().hex - new_type = uuid.uuid4().hex - - policy_ret = self.client.policies.update(policy.id, - blob=new_blob, - type=new_type) - - policy.ref.update({'blob': new_blob, 'type': new_type}) - self.check_policy(policy_ret, policy.ref) - - def test_delete_policy(self): - policy = self.client.policies.create(blob=uuid.uuid4().hex, - type=uuid.uuid4().hex) - - self.client.policies.delete(policy.id) - self.assertRaises(http.NotFound, - self.client.policies.get, - policy.id) diff --git a/keystoneclient/tests/functional/v3/test_projects.py b/keystoneclient/tests/functional/v3/test_projects.py deleted file mode 100644 index 4b8d7493..00000000 --- a/keystoneclient/tests/functional/v3/test_projects.py +++ /dev/null @@ -1,190 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient import exceptions -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class ProjectsTestMixin(object): - - def check_project(self, project, project_ref=None): - self.assertIsNotNone(project.id) - self.assertIn('self', project.links) - self.assertIn('/projects/' + project.id, project.links['self']) - - if project_ref: - self.assertEqual(project_ref['name'], project.name) - self.assertEqual(project_ref['domain'], project.domain_id) - self.assertEqual(project_ref['enabled'], project.enabled) - - # There is no guarantee the attributes below are present in project - if hasattr(project_ref, 'description'): - self.assertEqual(project_ref['description'], - project.description) - if hasattr(project_ref, 'parent'): - self.assertEqual(project_ref['parent'], project.parent) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(project.name) - self.assertIsNotNone(project.domain_id) - self.assertIsNotNone(project.enabled) - - -class ProjectsTestCase(base.V3ClientTestCase, ProjectsTestMixin): - - def setUp(self): - super(ProjectsTestCase, self).setUp() - self.test_domain = fixtures.Domain(self.client) - self.useFixture(self.test_domain) - - self.test_project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(self.test_project) - - def test_create_subproject(self): - project_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.test_domain.id, - 'enabled': True, - 'description': uuid.uuid4().hex, - 'parent': self.test_project.id} - - project = self.client.projects.create(**project_ref) - self.addCleanup(self.client.projects.delete, project) - self.check_project(project, project_ref) - - def test_create_project(self): - project_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.test_domain.id, - 'enabled': True, - 'description': uuid.uuid4().hex} - - project = self.client.projects.create(**project_ref) - self.addCleanup(self.client.projects.delete, project) - self.check_project(project, project_ref) - - def test_get_project(self): - project_ret = self.client.projects.get(self.test_project.id) - self.check_project(project_ret, self.test_project.ref) - - def test_get_project_invalid_params(self): - self.assertRaises(exceptions.ValidationError, - self.client.projects.get, - self.test_project.id, - subtree_as_list=True, subtree_as_ids=True) - self.assertRaises(exceptions.ValidationError, - self.client.projects.get, - self.test_project.id, - parents_as_list=True, parents_as_ids=True) - - def test_get_hierarchy_as_list(self): - project = fixtures.Project(self.client, self.test_domain.id, - parent=self.test_project.id) - self.useFixture(project) - - child_project = fixtures.Project(self.client, self.test_domain.id, - parent=project.id) - self.useFixture(child_project) - - # Only parents and subprojects that the current user has role - # assingments on are returned when asked for subtree_as_list and - # parents_as_list. - role = fixtures.Role(self.client) - self.useFixture(role) - self.client.roles.grant(role.id, user=self.user_id, - project=self.test_project.id) - self.client.roles.grant(role.id, user=self.user_id, - project=project.id) - self.client.roles.grant(role.id, user=self.user_id, - project=child_project.id) - - project_ret = self.client.projects.get(project.id, - subtree_as_list=True, - parents_as_list=True) - - self.check_project(project_ret, project.ref) - self.assertItemsEqual( - [{'project': self.test_project.entity.to_dict()}], - project_ret.parents) - self.assertItemsEqual( - [{'project': child_project.entity.to_dict()}], - project_ret.subtree) - - def test_get_hierarchy_as_ids(self): - project = fixtures.Project(self.client, self.test_domain.id, - parent=self.test_project.id) - self.useFixture(project) - - child_project = fixtures.Project(self.client, self.test_domain.id, - parent=project.id) - self.useFixture(child_project) - - project_ret = self.client.projects.get(project.id, - subtree_as_ids=True, - parents_as_ids=True) - - self.assertItemsEqual([self.test_project.id], project_ret.parents) - self.assertItemsEqual([child_project.id], project_ret.subtree) - - def test_list_projects(self): - project_one = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project_one) - - project_two = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project_two) - - projects = self.client.projects.list() - - # All projects are valid - for project in projects: - self.check_project(project) - - self.assertIn(project_one.entity, projects) - self.assertIn(project_two.entity, projects) - - def test_update_project(self): - project = fixtures.Project(self.client, self.test_domain.id) - self.useFixture(project) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_description = uuid.uuid4().hex - project_ret = self.client.projects.update(project.id, - name=new_name, - enabled=False, - description=new_description) - - project.ref.update({'name': new_name, 'enabled': False, - 'description': new_description}) - self.check_project(project_ret, project.ref) - - def test_update_project_domain_not_allowed(self): - domain = fixtures.Domain(self.client) - self.useFixture(domain) - # Cannot update domain after project is created. - self.assertRaises(http.BadRequest, - self.client.projects.update, - self.test_project.id, domain=domain.id) - - def test_delete_project(self): - project = self.client.projects.create(name=uuid.uuid4().hex, - domain=self.test_domain.id, - enabled=True) - - self.client.projects.delete(project.id) - self.assertRaises(http.NotFound, - self.client.projects.get, - project.id) diff --git a/keystoneclient/tests/functional/v3/test_regions.py b/keystoneclient/tests/functional/v3/test_regions.py deleted file mode 100644 index 51f93863..00000000 --- a/keystoneclient/tests/functional/v3/test_regions.py +++ /dev/null @@ -1,85 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class RegionsTestCase(base.V3ClientTestCase): - - def check_region(self, region, region_ref=None): - self.assertIsNotNone(region.id) - self.assertIn('self', region.links) - self.assertIn('/regions/' + region.id, region.links['self']) - - # There is no guarantee the below attributes are present in region - if hasattr(region_ref, 'description'): - self.assertEqual(region_ref['description'], region.description) - if hasattr(region_ref, 'parent_region'): - self.assertEqual( - region_ref['parent_region'], - region.parent_region) - - def test_create_region(self): - region_ref = {'description': uuid.uuid4().hex} - - region = self.client.regions.create(**region_ref) - self.addCleanup(self.client.regions.delete, region) - self.check_region(region, region_ref) - - def test_get_region(self): - region = fixtures.Region(self.client) - self.useFixture(region) - - region_ret = self.client.regions.get(region.id) - self.check_region(region_ret, region.ref) - - def test_list_regions(self): - region_one = fixtures.Region(self.client) - self.useFixture(region_one) - - region_two = fixtures.Region(self.client, parent_region=region_one.id) - self.useFixture(region_two) - - regions = self.client.regions.list() - - # All regions are valid - for region in regions: - self.check_region(region) - - self.assertIn(region_one.entity, regions) - self.assertIn(region_two.entity, regions) - - def test_update_region(self): - parent = fixtures.Region(self.client) - self.useFixture(parent) - - region = fixtures.Region(self.client) - self.useFixture(region) - - new_description = uuid.uuid4().hex - region_ret = self.client.regions.update(region.id, - description=new_description, - parent_region=parent.id) - self.check_region(region_ret, region.ref) - - def test_delete_region(self): - region = self.client.regions.create() - - self.client.regions.delete(region.id) - self.assertRaises(http.NotFound, - self.client.regions.get, - region.id) diff --git a/keystoneclient/tests/functional/v3/test_roles.py b/keystoneclient/tests/functional/v3/test_roles.py deleted file mode 100644 index d2bc7a25..00000000 --- a/keystoneclient/tests/functional/v3/test_roles.py +++ /dev/null @@ -1,236 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient import exceptions -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class RolesTestCase(base.V3ClientTestCase): - - def check_role(self, role, role_ref=None): - self.assertIsNotNone(role.id) - self.assertIn('self', role.links) - self.assertIn('/roles/' + role.id, role.links['self']) - - if role_ref: - self.assertEqual(role_ref['name'], role.name) - - # There is no guarantee domain is present in role - if hasattr(role_ref, 'domain'): - self.assertEqual(role_ref['domain'], role.domain_id) - - else: - # Only check remaining mandatory attribute - self.assertIsNotNone(role.name) - - def test_create_role(self): - role_ref = {'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex} - - role = self.client.roles.create(**role_ref) - self.addCleanup(self.client.roles.delete, role) - self.check_role(role, role_ref) - - def test_create_domain_role(self): - role_ref = {'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id} - - role = self.client.roles.create(**role_ref) - self.addCleanup(self.client.roles.delete, role) - self.check_role(role, role_ref) - - def test_get_role(self): - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - role_ret = self.client.roles.get(role.id) - self.check_role(role_ret, role.ref) - - def test_update_role_name(self): - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - role_ret = self.client.roles.update(role.id, - name=new_name) - - role.ref.update({'name': new_name}) - self.check_role(role_ret, role.ref) - - def test_update_role_domain(self): - role = fixtures.Role(self.client) - self.useFixture(role) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - new_domain = domain.id - role_ret = self.client.roles.update(role.id, - domain=new_domain) - - role.ref.update({'domain': new_domain}) - self.check_role(role_ret, role.ref) - - def test_list_roles_invalid_params(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - # Only filter in role grants for a user on a resource. - # Domain or project should be specified. - self.assertRaises(exceptions.ValidationError, - self.client.roles.list, - user=user.id) - - # Only filter in role grants for a group on a resource. - # Domain or project should be specified. - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - self.assertRaises(exceptions.ValidationError, - self.client.roles.list, - group=group.id) - - def test_list_roles(self): - global_role = fixtures.Role(self.client) - self.useFixture(global_role) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - domain_role = fixtures.Role(self.client, domain=domain.id) - self.useFixture(domain_role) - - global_roles = self.client.roles.list() - domain_roles = self.client.roles.list(domain_id=domain.id) - roles = global_roles + domain_roles - - # All roles are valid - for role in roles: - self.check_role(role) - - self.assertIn(global_role.entity, global_roles) - self.assertIn(domain_role.entity, domain_roles) - - def test_delete_role(self): - role = self.client.roles.create(name=uuid.uuid4().hex, - domain=self.project_domain_id) - - self.client.roles.delete(role.id) - self.assertRaises(http.NotFound, - self.client.roles.get, - role.id) - - def test_grant_role_invalid_params(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - # Only grant role to a group on a resource. - # Domain or project must be specified. - self.assertRaises(exceptions.ValidationError, - self.client.roles.grant, - role.id, - user=user.id) - - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - # Only grant role to a group on a resource. - # Domain or project must be specified. - self.assertRaises(exceptions.ValidationError, - self.client.roles.grant, - role.id, - group=group.id) - - def test_user_domain_grant_and_revoke(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, user=user.id, domain=domain.id) - roles_after_grant = self.client.roles.list(user=user.id, - domain=domain.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, user=user.id, domain=domain.id) - roles_after_revoke = self.client.roles.list(user=user.id, - domain=domain.id) - self.assertEqual(roles_after_revoke, []) - - def test_user_project_grant_and_revoke(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, user=user.id, project=project.id) - roles_after_grant = self.client.roles.list(user=user.id, - project=project.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, user=user.id, project=project.id) - roles_after_revoke = self.client.roles.list(user=user.id, - project=project.id) - self.assertEqual(roles_after_revoke, []) - - def test_group_domain_grant_and_revoke(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - domain = fixtures.Domain(self.client) - self.useFixture(domain) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, group=group.id, domain=domain.id) - roles_after_grant = self.client.roles.list(group=group.id, - domain=domain.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, group=group.id, domain=domain.id) - roles_after_revoke = self.client.roles.list(group=group.id, - domain=domain.id) - self.assertEqual(roles_after_revoke, []) - - def test_group_project_grant_and_revoke(self): - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(group) - - project = fixtures.Project(self.client, self.project_domain_id) - self.useFixture(project) - - role = fixtures.Role(self.client, domain=self.project_domain_id) - self.useFixture(role) - - self.client.roles.grant(role, group=group.id, project=project.id) - roles_after_grant = self.client.roles.list(group=group.id, - project=project.id) - self.assertItemsEqual(roles_after_grant, [role.entity]) - - self.client.roles.revoke(role, group=group.id, project=project.id) - roles_after_revoke = self.client.roles.list(group=group.id, - project=project.id) - self.assertEqual(roles_after_revoke, []) diff --git a/keystoneclient/tests/functional/v3/test_services.py b/keystoneclient/tests/functional/v3/test_services.py deleted file mode 100644 index c17747d3..00000000 --- a/keystoneclient/tests/functional/v3/test_services.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http - -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class ServicesTestCase(base.V3ClientTestCase): - - def check_service(self, service, service_ref=None): - self.assertIsNotNone(service.id) - self.assertIn('self', service.links) - self.assertIn('/services/' + service.id, service.links['self']) - - if service_ref: - self.assertEqual(service_ref['name'], service.name) - self.assertEqual(service_ref['enabled'], service.enabled) - self.assertEqual(service_ref['type'], service.type) - - # There is no guarantee description is present in service - if hasattr(service_ref, 'description'): - self.assertEqual(service_ref['description'], - service.description) - - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(service.name) - self.assertIsNotNone(service.enabled) - self.assertIsNotNone(service.type) - - def test_create_service(self): - service_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'type': uuid.uuid4().hex, - 'enabled': True, - 'description': uuid.uuid4().hex} - - service = self.client.services.create(**service_ref) - - self.addCleanup(self.client.services.delete, service) - self.check_service(service, service_ref) - - def test_get_service(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - service_ret = self.client.services.get(service.id) - self.check_service(service_ret, service.ref) - - def test_list_services(self): - service_one = fixtures.Service(self.client) - self.useFixture(service_one) - - service_two = fixtures.Service(self.client) - self.useFixture(service_two) - - services = self.client.services.list() - - # All services are valid - for service in services: - self.check_service(service) - - self.assertIn(service_one.entity, services) - self.assertIn(service_two.entity, services) - - def test_update_service(self): - service = fixtures.Service(self.client) - self.useFixture(service) - - new_name = fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex - new_type = uuid.uuid4().hex - new_enabled = False - new_description = uuid.uuid4().hex - - service_ret = self.client.services.update(service.id, - name=new_name, - type=new_type, - enabled=new_enabled, - description=new_description) - - service.ref.update({'name': new_name, 'type': new_type, - 'enabled': new_enabled, - 'description': new_description}) - self.check_service(service_ret, service.ref) - - def test_delete_service(self): - service = self.client.services.create(name=uuid.uuid4().hex, - type=uuid.uuid4().hex) - - self.client.services.delete(service.id) - self.assertRaises(http.NotFound, - self.client.services.get, - service.id) diff --git a/keystoneclient/tests/functional/v3/test_users.py b/keystoneclient/tests/functional/v3/test_users.py deleted file mode 100644 index 780ddbac..00000000 --- a/keystoneclient/tests/functional/v3/test_users.py +++ /dev/null @@ -1,140 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1.exceptions import http -from keystoneclient.tests.functional import base -from keystoneclient.tests.functional.v3 import client_fixtures as fixtures - - -class UsersTestCase(base.V3ClientTestCase): - - def check_user(self, user, user_ref=None): - self.assertIsNotNone(user.id) - self.assertIsNotNone(user.enabled) - self.assertIn('self', user.links) - self.assertIn('/users/' + user.id, user.links['self']) - - if user_ref: - self.assertEqual(user_ref['name'], user.name) - self.assertEqual(user_ref['domain'], user.domain_id) - # There is no guarantee the attributes below are present in user - if hasattr(user_ref, 'description'): - self.assertEqual(user_ref['description'], user.description) - if hasattr(user_ref, 'email'): - self.assertEqual(user_ref['email'], user.email) - if hasattr(user_ref, 'default_project'): - self.assertEqual(user_ref['default_project'], - user.default_project_id) - else: - # Only check remaining mandatory attributes - self.assertIsNotNone(user.name) - self.assertIsNotNone(user.domain_id) - - def test_create_user(self): - user_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id, - 'default_project': self.project_id, - 'password': uuid.uuid4().hex, - 'description': uuid.uuid4().hex} - - user = self.client.users.create(**user_ref) - self.addCleanup(self.client.users.delete, user) - self.check_user(user, user_ref) - - def test_get_user(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - user_ret = self.client.users.get(user.id) - self.check_user(user_ret, user.ref) - - def test_list_users(self): - user_one = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_one) - - user_two = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user_two) - - users = self.client.users.list() - - # All users are valid - for user in users: - self.check_user(user) - - self.assertIn(user_one.entity, users) - self.assertIn(user_two.entity, users) - - def test_list_users_with_filters(self): - suffix = uuid.uuid4().hex - user1_ref = { - 'name': 'test_user' + suffix, - 'domain': self.project_domain_id, - 'default_project': self.project_id, - 'password': uuid.uuid4().hex, - 'description': uuid.uuid4().hex} - - user2_ref = { - 'name': fixtures.RESOURCE_NAME_PREFIX + uuid.uuid4().hex, - 'domain': self.project_domain_id, - 'default_project': self.project_id, - 'password': uuid.uuid4().hex, - 'description': uuid.uuid4().hex} - - user1 = self.client.users.create(**user1_ref) - self.client.users.create(**user2_ref) - - users = self.client.users.list(name__contains=['test_user', suffix]) - self.assertEqual(1, len(users)) - self.assertIn(user1, users) - - def test_update_user(self): - user = fixtures.User(self.client, self.project_domain_id) - self.useFixture(user) - - new_description = uuid.uuid4().hex - user_ret = self.client.users.update(user.id, - description=new_description) - - user.ref.update({'description': new_description}) - self.check_user(user_ret, user.ref) - - def test_user_grouping(self): - # keystoneclient.v3.users owns user grouping operations, this is why - # this test case belongs to this class - user = fixtures.User(self.client, self.project_domain_id) - group = fixtures.Group(self.client, self.project_domain_id) - self.useFixture(user) - self.useFixture(group) - - self.assertRaises(http.NotFound, - self.client.users.check_in_group, - user.id, group.id) - - self.client.users.add_to_group(user.id, group.id) - self.client.users.check_in_group(user.id, group.id) - self.client.users.remove_from_group(user.id, group.id) - - self.assertRaises(http.NotFound, - self.client.users.check_in_group, - user.id, group.id) - - def test_delete_user(self): - user = self.client.users.create(name=uuid.uuid4().hex, - domain=self.project_domain_id) - - self.client.users.delete(user.id) - self.assertRaises(http.NotFound, - self.client.users.get, - user.id) diff --git a/keystoneclient/tests/unit/__init__.py b/keystoneclient/tests/unit/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/apiclient/__init__.py b/keystoneclient/tests/unit/apiclient/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/apiclient/test_exceptions.py b/keystoneclient/tests/unit/apiclient/test_exceptions.py deleted file mode 100644 index 65cf0801..00000000 --- a/keystoneclient/tests/unit/apiclient/test_exceptions.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import exceptions -from keystoneclient.tests.unit import utils - - -class FakeResponse(object): - json_data = {} - - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) - - def json(self): - return self.json_data - - -class ExceptionsArgsTest(utils.TestCase): - - def assert_exception(self, ex_cls, method, url, status_code, json_data): - ex = exceptions.from_response( - FakeResponse(status_code=status_code, - headers={"Content-Type": "application/json"}, - json_data=json_data), - method, - url) - self.assertIsInstance(ex, ex_cls) - self.assertIn(json_data["error"]["message"], ex.message) - self.assertEqual(ex.details, json_data["error"]["details"]) - self.assertEqual(ex.method, method) - self.assertEqual(ex.url, url) - self.assertEqual(ex.http_status, status_code) - - def test_from_response_known(self): - method = "GET" - url = "/fake" - status_code = 400 - json_data = {"error": {"message": "fake message", - "details": "fake details"}} - self.assert_exception( - exceptions.BadRequest, method, url, status_code, json_data) - - def test_from_response_unknown(self): - method = "POST" - url = "/fake-unknown" - status_code = 499 - json_data = {"error": {"message": "fake unknown message", - "details": "fake unknown details"}} - self.assert_exception( - exceptions.HTTPClientError, method, url, status_code, json_data) - status_code = 600 - self.assert_exception( - exceptions.HTTPError, method, url, status_code, json_data) diff --git a/keystoneclient/tests/unit/auth/__init__.py b/keystoneclient/tests/unit/auth/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/auth/test_access.py b/keystoneclient/tests/unit/auth/test_access.py deleted file mode 100644 index f5f5843a..00000000 --- a/keystoneclient/tests/unit/auth/test_access.py +++ /dev/null @@ -1,64 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1 import fixture -from keystoneauth1 import plugin - -from keystoneclient import access -from keystoneclient.auth.identity import access as access_plugin -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class AccessInfoPluginTests(utils.TestCase): - - def setUp(self): - super(AccessInfoPluginTests, self).setUp() - with self.deprecations.expect_deprecations_here(): - self.session = session.Session() - self.auth_token = uuid.uuid4().hex - - def _plugin(self, **kwargs): - token = fixture.V3Token() - s = token.add_service('identity') - s.add_standard_endpoints(public=self.TEST_ROOT_URL) - - auth_ref = access.AccessInfo.factory(body=token, - auth_token=self.auth_token) - with self.deprecations.expect_deprecations_here(): - return access_plugin.AccessInfoPlugin(auth_ref, **kwargs) - - def test_auth_ref(self): - plugin = self._plugin() - self.assertEqual(self.TEST_ROOT_URL, - plugin.get_endpoint(self.session, - service_type='identity', - interface='public')) - self.assertEqual(self.auth_token, plugin.get_token(session)) - - def test_auth_url(self): - auth_url = 'http://keystone.test.url' - plug = self._plugin(auth_url=auth_url) - - self.assertEqual(auth_url, - plug.get_endpoint(self.session, - interface=plugin.AUTH_INTERFACE)) - - def test_invalidate(self): - plugin = self._plugin() - auth_ref = plugin.auth_ref - - self.assertIsInstance(auth_ref, access.AccessInfo) - self.assertFalse(plugin.invalidate()) - self.assertIs(auth_ref, plugin.auth_ref) diff --git a/keystoneclient/tests/unit/auth/test_auth.py b/keystoneclient/tests/unit/auth/test_auth.py deleted file mode 100644 index f2884350..00000000 --- a/keystoneclient/tests/unit/auth/test_auth.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import auth -from keystoneclient.auth import identity -from keystoneclient.tests.unit.auth import utils - - -class AuthTests(utils.TestCase): - - def test_plugin_names_in_available(self): - with self.deprecations.expect_deprecations_here(): - plugins = auth.get_available_plugin_names() - - for p in ('password', 'v2password', 'v3password', - 'token', 'v2token', 'v3token'): - self.assertIn(p, plugins) - - def test_plugin_classes_in_available(self): - with self.deprecations.expect_deprecations_here(): - plugins = auth.get_available_plugin_classes() - - self.assertIs(plugins['password'], identity.Password) - self.assertIs(plugins['v2password'], identity.V2Password) - self.assertIs(plugins['v3password'], identity.V3Password) - - self.assertIs(plugins['token'], identity.Token) - self.assertIs(plugins['v2token'], identity.V2Token) - self.assertIs(plugins['v3token'], identity.V3Token) diff --git a/keystoneclient/tests/unit/auth/test_cli.py b/keystoneclient/tests/unit/auth/test_cli.py deleted file mode 100644 index b6fefa7c..00000000 --- a/keystoneclient/tests/unit/auth/test_cli.py +++ /dev/null @@ -1,197 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import uuid - -import fixtures -import mock -from oslo_config import cfg - -from keystoneclient.auth import base -from keystoneclient.auth import cli -from keystoneclient.tests.unit.auth import utils - - -class TesterPlugin(base.BaseAuthPlugin): - - def get_token(self, *args, **kwargs): - return None - - @classmethod - def get_options(cls): - # NOTE(jamielennox): this is kind of horrible. If you specify this as - # a deprecated_name= value it will convert - to _ which is not what we - # want for a CLI option. - deprecated = [cfg.DeprecatedOpt('test-other')] - return [ - cfg.StrOpt('test-opt', help='tester', deprecated_opts=deprecated) - ] - - -class CliTests(utils.TestCase): - - def setUp(self): - super(CliTests, self).setUp() - self.deprecations.expect_deprecations() - self.p = argparse.ArgumentParser() - - def env(self, name, value=None): - if value is not None: - # environment variables are always strings - value = str(value) - - return self.useFixture(fixtures.EnvironmentVariable(name, value)) - - def test_creating_with_no_args(self): - ret = cli.register_argparse_arguments(self.p, []) - self.assertIsNone(ret) - self.assertIn('--os-auth-plugin', self.p.format_usage()) - - def test_load_with_nothing(self): - cli.register_argparse_arguments(self.p, []) - opts = self.p.parse_args([]) - self.assertIsNone(cli.load_from_argparse_arguments(opts)) - - @utils.mock_plugin - def test_basic_params_added(self, m): - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name] - ret = cli.register_argparse_arguments(self.p, argv) - self.assertIs(utils.MockPlugin, ret) - - for n in ('--os-a-int', '--os-a-bool', '--os-a-float'): - self.assertIn(n, self.p.format_usage()) - - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_param_loading(self, m): - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name, - '--os-a-int', str(self.a_int), - '--os-a-float', str(self.a_float), - '--os-a-bool', str(self.a_bool)] - - klass = cli.register_argparse_arguments(self.p, argv) - self.assertIs(utils.MockPlugin, klass) - - opts = self.p.parse_args(argv) - self.assertEqual(name, opts.os_auth_plugin) - - a = cli.load_from_argparse_arguments(opts) - self.assertTestVals(a) - - self.assertEqual(name, opts.os_auth_plugin) - self.assertEqual(str(self.a_int), opts.os_a_int) - self.assertEqual(str(self.a_float), opts.os_a_float) - self.assertEqual(str(self.a_bool), opts.os_a_bool) - - @utils.mock_plugin - def test_default_options(self, m): - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name, - '--os-a-float', str(self.a_float)] - - klass = cli.register_argparse_arguments(self.p, argv) - self.assertIs(utils.MockPlugin, klass) - - opts = self.p.parse_args(argv) - self.assertEqual(name, opts.os_auth_plugin) - - a = cli.load_from_argparse_arguments(opts) - - self.assertEqual(self.a_float, a['a_float']) - self.assertEqual(3, a['a_int']) - - @utils.mock_plugin - def test_with_default_string_value(self, m): - name = uuid.uuid4().hex - klass = cli.register_argparse_arguments(self.p, [], default=name) - self.assertIs(utils.MockPlugin, klass) - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_overrides_default_string_value(self, m): - name = uuid.uuid4().hex - default = uuid.uuid4().hex - argv = ['--os-auth-plugin', name] - klass = cli.register_argparse_arguments(self.p, argv, default=default) - self.assertIs(utils.MockPlugin, klass) - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_with_default_type_value(self, m): - klass = cli.register_argparse_arguments(self.p, [], - default=utils.MockPlugin) - self.assertIs(utils.MockPlugin, klass) - self.assertEqual(0, m.call_count) - - @utils.mock_plugin - def test_overrides_default_type_value(self, m): - # using this test plugin would fail if called because there - # is no get_options() function - class TestPlugin(object): - pass - name = uuid.uuid4().hex - argv = ['--os-auth-plugin', name] - klass = cli.register_argparse_arguments(self.p, argv, - default=TestPlugin) - self.assertIs(utils.MockPlugin, klass) - m.assert_called_once_with(name) - - @utils.mock_plugin - def test_env_overrides_default_opt(self, m): - name = uuid.uuid4().hex - val = uuid.uuid4().hex - self.env('OS_A_STR', val) - - klass = cli.register_argparse_arguments(self.p, [], default=name) - opts = self.p.parse_args([]) - a = klass.load_from_argparse_arguments(opts) - - self.assertEqual(val, a['a_str']) - - def test_deprecated_cli_options(self): - TesterPlugin.register_argparse_arguments(self.p) - val = uuid.uuid4().hex - opts = self.p.parse_args(['--os-test-other', val]) - self.assertEqual(val, opts.os_test_opt) - - def test_deprecated_multi_cli_options(self): - TesterPlugin.register_argparse_arguments(self.p) - val1 = uuid.uuid4().hex - val2 = uuid.uuid4().hex - # argarse rules say that the last specified wins. - opts = self.p.parse_args(['--os-test-other', val2, - '--os-test-opt', val1]) - self.assertEqual(val1, opts.os_test_opt) - - def test_deprecated_env_options(self): - val = uuid.uuid4().hex - - with mock.patch.dict('os.environ', {'OS_TEST_OTHER': val}): - TesterPlugin.register_argparse_arguments(self.p) - - opts = self.p.parse_args([]) - self.assertEqual(val, opts.os_test_opt) - - def test_deprecated_env_multi_options(self): - val1 = uuid.uuid4().hex - val2 = uuid.uuid4().hex - - with mock.patch.dict('os.environ', {'OS_TEST_OPT': val1, - 'OS_TEST_OTHER': val2}): - TesterPlugin.register_argparse_arguments(self.p) - - opts = self.p.parse_args([]) - self.assertEqual(val1, opts.os_test_opt) diff --git a/keystoneclient/tests/unit/auth/test_conf.py b/keystoneclient/tests/unit/auth/test_conf.py deleted file mode 100644 index 47bf7590..00000000 --- a/keystoneclient/tests/unit/auth/test_conf.py +++ /dev/null @@ -1,178 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import mock -from oslo_config import cfg -from oslo_config import fixture as config -import stevedore - -from keystoneclient.auth import base -from keystoneclient.auth import conf -from keystoneclient.auth.identity import v2 as v2_auth -from keystoneclient.auth.identity import v3 as v3_auth -from keystoneclient import exceptions -from keystoneclient.tests.unit.auth import utils - - -class ConfTests(utils.TestCase): - - def setUp(self): - super(ConfTests, self).setUp() - self.deprecations.expect_deprecations() - self.conf_fixture = self.useFixture(config.Config()) - - # NOTE(jamielennox): we register the basic config options first because - # we need them in place before we can stub them. We will need to run - # the register again after we stub the auth section and auth plugin so - # it can load the plugin specific options. - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - def test_loading_v2(self): - section = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - trust_id = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(v2_auth.Password.get_options(), - group=section) - - self.conf_fixture.config(auth_plugin=self.V2PASS, - username=username, - password=password, - trust_id=trust_id, - tenant_id=tenant_id, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - self.assertEqual(trust_id, a.trust_id) - self.assertEqual(tenant_id, a.tenant_id) - - def test_loading_v3(self): - section = uuid.uuid4().hex - token = uuid.uuid4().hex - trust_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - project_domain_name = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(v3_auth.Token.get_options(), - group=section) - - self.conf_fixture.config(auth_plugin=self.V3TOKEN, - token=token, - trust_id=trust_id, - project_id=project_id, - project_domain_name=project_domain_name, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - - self.assertEqual(token, a.auth_methods[0].token) - self.assertEqual(trust_id, a.trust_id) - self.assertEqual(project_id, a.project_id) - self.assertEqual(project_domain_name, a.project_domain_name) - - def test_loading_invalid_plugin(self): - auth_plugin = uuid.uuid4().hex - self.conf_fixture.config(auth_plugin=auth_plugin, - group=self.GROUP) - - e = self.assertRaises(exceptions.NoMatchingPlugin, - conf.load_from_conf_options, - self.conf_fixture.conf, - self.GROUP) - - self.assertEqual(auth_plugin, e.name) - - def test_loading_with_no_data(self): - self.assertIsNone(conf.load_from_conf_options(self.conf_fixture.conf, - self.GROUP)) - - @mock.patch('stevedore.DriverManager') - def test_other_params(self, m): - m.return_value = utils.MockManager(utils.MockPlugin) - driver_name = uuid.uuid4().hex - - self.conf_fixture.register_opts(utils.MockPlugin.get_options(), - group=self.GROUP) - self.conf_fixture.config(auth_plugin=driver_name, - group=self.GROUP, - **self.TEST_VALS) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertTestVals(a) - - m.assert_called_once_with(namespace=base.PLUGIN_NAMESPACE, - name=driver_name, - invoke_on_load=False) - - @utils.mock_plugin - def test_same_section(self, m): - self.conf_fixture.register_opts(utils.MockPlugin.get_options(), - group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - self.conf_fixture.config(auth_plugin=uuid.uuid4().hex, - group=self.GROUP, - **self.TEST_VALS) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertTestVals(a) - - @utils.mock_plugin - def test_diff_section(self, m): - section = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(utils.MockPlugin.get_options(), - group=section) - self.conf_fixture.config(group=section, - auth_plugin=uuid.uuid4().hex, - **self.TEST_VALS) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertTestVals(a) - - def test_plugins_are_all_opts(self): - manager = stevedore.ExtensionManager(base.PLUGIN_NAMESPACE, - invoke_on_load=False, - propagate_map_exceptions=True) - - def inner(driver): - for p in driver.plugin.get_options(): - self.assertIsInstance(p, cfg.Opt) - - manager.map(inner) - - def test_get_common(self): - opts = conf.get_common_conf_options() - for opt in opts: - self.assertIsInstance(opt, cfg.Opt) - self.assertEqual(2, len(opts)) - - def test_get_named(self): - loaded_opts = conf.get_plugin_options('v2password') - plugin_opts = v2_auth.Password.get_options() - - self.assertEqual(plugin_opts, loaded_opts) diff --git a/keystoneclient/tests/unit/auth/test_default_cli.py b/keystoneclient/tests/unit/auth/test_default_cli.py deleted file mode 100644 index cb4603dc..00000000 --- a/keystoneclient/tests/unit/auth/test_default_cli.py +++ /dev/null @@ -1,92 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import uuid - -import mock - -from keystoneclient.auth.identity.generic import cli -from keystoneclient import exceptions -from keystoneclient.tests.unit import utils - - -class DefaultCliTests(utils.TestCase): - - def setUp(self): - super(DefaultCliTests, self).setUp() - self.deprecations.expect_deprecations() - - def new_plugin(self, argv): - parser = argparse.ArgumentParser() - cli.DefaultCLI.register_argparse_arguments(parser) - opts = parser.parse_args(argv) - return cli.DefaultCLI.load_from_argparse_arguments(opts) - - def test_endpoint_override(self): - password = uuid.uuid4().hex - url = uuid.uuid4().hex - - p = self.new_plugin(['--os-auth-url', 'url', - '--os-endpoint', url, - '--os-password', password]) - - self.assertEqual(url, p.get_endpoint(None)) - self.assertEqual(password, p._password) - - def test_token_only_override(self): - self.assertRaises(exceptions.CommandError, - self.new_plugin, - ['--os-token', uuid.uuid4().hex]) - - def test_token_endpoint_override(self): - token = uuid.uuid4().hex - endpoint = uuid.uuid4().hex - - p = self.new_plugin(['--os-endpoint', endpoint, - '--os-token', token]) - - self.assertEqual(endpoint, p.get_endpoint(None)) - self.assertEqual(token, p.get_token(None)) - - def test_no_auth_url(self): - exc = self.assertRaises(exceptions.CommandError, - self.new_plugin, - ['--os-username', uuid.uuid4().hex]) - - self.assertIn('auth-url', str(exc)) - - @mock.patch('sys.stdin', autospec=True) - @mock.patch('getpass.getpass') - def test_prompt_password(self, mock_getpass, mock_stdin): - password = uuid.uuid4().hex - - mock_stdin.isatty = lambda: True - mock_getpass.return_value = password - - p = self.new_plugin(['--os-auth-url', uuid.uuid4().hex, - '--os-username', uuid.uuid4().hex]) - - self.assertEqual(password, p._password) - - @mock.patch('sys.stdin', autospec=True) - @mock.patch('getpass.getpass') - def test_prompt_no_password(self, mock_getpass, mock_stdin): - mock_stdin.isatty = lambda: True - mock_getpass.return_value = '' - - exc = self.assertRaises(exceptions.CommandError, - self.new_plugin, - ['--os-auth-url', uuid.uuid4().hex, - '--os-username', uuid.uuid4().hex]) - - self.assertIn('password', str(exc)) diff --git a/keystoneclient/tests/unit/auth/test_identity_common.py b/keystoneclient/tests/unit/auth/test_identity_common.py deleted file mode 100644 index be8a062d..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_common.py +++ /dev/null @@ -1,505 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import datetime -import uuid - -from keystoneauth1 import fixture -from keystoneauth1 import plugin -import mock -from oslo_utils import timeutils -import six - -from keystoneclient import access -from keystoneclient.auth import base -from keystoneclient.auth import identity -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -@six.add_metaclass(abc.ABCMeta) -class CommonIdentityTests(object): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - - TEST_COMPUTE_PUBLIC = 'http://nova/novapi/public' - TEST_COMPUTE_INTERNAL = 'http://nova/novapi/internal' - TEST_COMPUTE_ADMIN = 'http://nova/novapi/admin' - - TEST_PASS = uuid.uuid4().hex - - def setUp(self): - super(CommonIdentityTests, self).setUp() - self.deprecations.expect_deprecations() - - self.TEST_URL = '%s%s' % (self.TEST_ROOT_URL, self.version) - self.TEST_ADMIN_URL = '%s%s' % (self.TEST_ROOT_ADMIN_URL, self.version) - self.TEST_DISCOVERY = fixture.DiscoveryList(href=self.TEST_ROOT_URL) - - self.stub_auth_data() - - @abc.abstractmethod - def create_auth_plugin(self, **kwargs): - """Create an auth plugin that makes sense for the auth data. - - It doesn't really matter what auth mechanism is used but it should be - appropriate to the API version. - """ - pass - - @abc.abstractmethod - def get_auth_data(self, **kwargs): - """Return fake authentication data. - - This should register a valid token response and ensure that the compute - endpoints are set to TEST_COMPUTE_PUBLIC, _INTERNAL and _ADMIN. - """ - pass - - def stub_auth_data(self, **kwargs): - token = self.get_auth_data(**kwargs) - self.user_id = token.user_id - - try: - self.project_id = token.project_id - except AttributeError: - self.project_id = token.tenant_id - - self.stub_auth(json=token) - - @abc.abstractproperty - def version(self): - """The API version being tested.""" - - def test_discovering(self): - self.stub_url('GET', [], - base_url=self.TEST_COMPUTE_ADMIN, - json=self.TEST_DISCOVERY) - - body = 'SUCCESS' - - # which gives our sample values - self.stub_url('GET', ['path'], text=body) - - a = self.create_auth_plugin() - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - new_body = 'SC SUCCESS' - # if we don't specify a version, we use the URL from the SC - self.stub_url('GET', ['path'], - base_url=self.TEST_COMPUTE_ADMIN, - text=new_body) - - resp = s.get('/path', endpoint_filter={'service_type': 'compute', - 'interface': 'admin'}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(new_body, resp.text) - - def test_discovery_uses_session_cache(self): - # register responses such that if the discovery URL is hit more than - # once then the response will be invalid and not point to COMPUTE_ADMIN - resps = [{'json': self.TEST_DISCOVERY}, {'status_code': 500}] - self.requests_mock.get(self.TEST_COMPUTE_ADMIN, resps) - - body = 'SUCCESS' - self.stub_url('GET', ['path'], text=body) - - # now either of the two plugins I use, it should not cause a second - # request to the discovery url. - s = session.Session() - a = self.create_auth_plugin() - b = self.create_auth_plugin() - - for auth in (a, b): - resp = s.get('/path', - auth=auth, - endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - def test_discovery_uses_plugin_cache(self): - # register responses such that if the discovery URL is hit more than - # once then the response will be invalid and not point to COMPUTE_ADMIN - resps = [{'json': self.TEST_DISCOVERY}, {'status_code': 500}] - self.requests_mock.get(self.TEST_COMPUTE_ADMIN, resps) - - body = 'SUCCESS' - self.stub_url('GET', ['path'], text=body) - - # now either of the two sessions I use, it should not cause a second - # request to the discovery url. - sa = session.Session() - sb = session.Session() - auth = self.create_auth_plugin() - - for sess in (sa, sb): - resp = sess.get('/path', - auth=auth, - endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - def test_discovering_with_no_data(self): - # which returns discovery information pointing to TEST_URL but there is - # no data there. - self.stub_url('GET', [], - base_url=self.TEST_COMPUTE_ADMIN, - status_code=400) - - # so the url that will be used is the same TEST_COMPUTE_ADMIN - body = 'SUCCESS' - self.stub_url('GET', ['path'], base_url=self.TEST_COMPUTE_ADMIN, - text=body, status_code=200) - - a = self.create_auth_plugin() - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter={'service_type': 'compute', - 'interface': 'admin', - 'version': self.version}) - - self.assertEqual(200, resp.status_code) - self.assertEqual(body, resp.text) - - def test_asking_for_auth_endpoint_ignores_checks(self): - a = self.create_auth_plugin() - s = session.Session(auth=a) - - auth_url = s.get_endpoint(service_type='compute', - interface=plugin.AUTH_INTERFACE) - - self.assertEqual(self.TEST_URL, auth_url) - - def _create_expired_auth_plugin(self, **kwargs): - expires = timeutils.utcnow() - datetime.timedelta(minutes=20) - expired_token = self.get_auth_data(expires=expires) - expired_auth_ref = access.AccessInfo.factory(body=expired_token) - - body = 'SUCCESS' - self.stub_url('GET', ['path'], - base_url=self.TEST_COMPUTE_ADMIN, text=body) - - a = self.create_auth_plugin(**kwargs) - a.auth_ref = expired_auth_ref - return a - - def test_reauthenticate(self): - a = self._create_expired_auth_plugin() - expired_auth_ref = a.auth_ref - s = session.Session(auth=a) - self.assertIsNot(expired_auth_ref, a.get_access(s)) - - def test_no_reauthenticate(self): - a = self._create_expired_auth_plugin(reauthenticate=False) - expired_auth_ref = a.auth_ref - s = session.Session(auth=a) - self.assertIs(expired_auth_ref, a.get_access(s)) - - def test_invalidate(self): - a = self.create_auth_plugin() - s = session.Session(auth=a) - - # trigger token fetching - s.get_auth_headers() - - self.assertTrue(a.auth_ref) - self.assertTrue(a.invalidate()) - self.assertIsNone(a.auth_ref) - self.assertFalse(a.invalidate()) - - def test_get_auth_properties(self): - a = self.create_auth_plugin() - s = session.Session() - - self.assertEqual(self.user_id, a.get_user_id(s)) - self.assertEqual(self.project_id, a.get_project_id(s)) - - -class V3(CommonIdentityTests, utils.TestCase): - - @property - def version(self): - return 'v3' - - def get_auth_data(self, **kwargs): - token = fixture.V3Token(**kwargs) - region = 'RegionOne' - - svc = token.add_service('identity') - svc.add_standard_endpoints(admin=self.TEST_ADMIN_URL, region=region) - - svc = token.add_service('compute') - svc.add_standard_endpoints(admin=self.TEST_COMPUTE_ADMIN, - public=self.TEST_COMPUTE_PUBLIC, - internal=self.TEST_COMPUTE_INTERNAL, - region=region) - - return token - - def stub_auth(self, subject_token=None, **kwargs): - if not subject_token: - subject_token = self.TEST_TOKEN - - kwargs.setdefault('headers', {})['X-Subject-Token'] = subject_token - self.stub_url('POST', ['auth', 'tokens'], **kwargs) - - def create_auth_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.TEST_URL) - kwargs.setdefault('username', self.TEST_USER) - kwargs.setdefault('password', self.TEST_PASS) - return identity.V3Password(**kwargs) - - -class V2(CommonIdentityTests, utils.TestCase): - - @property - def version(self): - return 'v2.0' - - def create_auth_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.TEST_URL) - kwargs.setdefault('username', self.TEST_USER) - kwargs.setdefault('password', self.TEST_PASS) - return identity.V2Password(**kwargs) - - def get_auth_data(self, **kwargs): - token = fixture.V2Token(**kwargs) - region = 'RegionOne' - - svc = token.add_service('identity') - svc.add_endpoint(self.TEST_ADMIN_URL, region=region) - - svc = token.add_service('compute') - svc.add_endpoint(public=self.TEST_COMPUTE_PUBLIC, - internal=self.TEST_COMPUTE_INTERNAL, - admin=self.TEST_COMPUTE_ADMIN, - region=region) - - return token - - def stub_auth(self, **kwargs): - self.stub_url('POST', ['tokens'], **kwargs) - - -class CatalogHackTests(utils.TestCase): - - TEST_URL = 'http://keystone.server:5000/v2.0' - OTHER_URL = 'http://other.server:5000/path' - - IDENTITY = 'identity' - - BASE_URL = 'http://keystone.server:5000/' - V2_URL = BASE_URL + 'v2.0' - V3_URL = BASE_URL + 'v3' - - def setUp(self): - super(CatalogHackTests, self).setUp() - self.deprecations.expect_deprecations() - - def test_getting_endpoints(self): - disc = fixture.DiscoveryList(href=self.BASE_URL) - self.stub_url('GET', - ['/'], - base_url=self.BASE_URL, - json=disc) - - token = fixture.V2Token() - service = token.add_service(self.IDENTITY) - service.add_endpoint(public=self.V2_URL, - admin=self.V2_URL, - internal=self.V2_URL) - - self.stub_url('POST', - ['tokens'], - base_url=self.V2_URL, - json=token) - - v2_auth = identity.V2Password(self.V2_URL, - username=uuid.uuid4().hex, - password=uuid.uuid4().hex) - - sess = session.Session(auth=v2_auth) - - endpoint = sess.get_endpoint(service_type=self.IDENTITY, - interface='public', - version=(3, 0)) - - self.assertEqual(self.V3_URL, endpoint) - - def test_returns_original_when_discover_fails(self): - token = fixture.V2Token() - service = token.add_service(self.IDENTITY) - service.add_endpoint(public=self.V2_URL, - admin=self.V2_URL, - internal=self.V2_URL) - - self.stub_url('POST', - ['tokens'], - base_url=self.V2_URL, - json=token) - - self.stub_url('GET', [], base_url=self.BASE_URL, status_code=404) - - v2_auth = identity.V2Password(self.V2_URL, - username=uuid.uuid4().hex, - password=uuid.uuid4().hex) - - sess = session.Session(auth=v2_auth) - - endpoint = sess.get_endpoint(service_type=self.IDENTITY, - interface='public', - version=(3, 0)) - - self.assertEqual(self.V2_URL, endpoint) - - def test_getting_endpoints_on_auth_interface(self): - disc = fixture.DiscoveryList(href=self.BASE_URL) - self.stub_url('GET', - ['/'], - base_url=self.BASE_URL, - status_code=300, - json=disc) - - token = fixture.V2Token() - service = token.add_service(self.IDENTITY) - service.add_endpoint(public=self.V2_URL, - admin=self.V2_URL, - internal=self.V2_URL) - - self.stub_url('POST', - ['tokens'], - base_url=self.V2_URL, - json=token) - - v2_auth = identity.V2Password(self.V2_URL, - username=uuid.uuid4().hex, - password=uuid.uuid4().hex) - - sess = session.Session(auth=v2_auth) - - endpoint = sess.get_endpoint(interface=plugin.AUTH_INTERFACE, - version=(3, 0)) - - self.assertEqual(self.V3_URL, endpoint) - - -class GenericPlugin(base.BaseAuthPlugin): - - BAD_TOKEN = uuid.uuid4().hex - - def __init__(self): - super(GenericPlugin, self).__init__() - - self.endpoint = 'http://keystone.host:5000' - - self.headers = {'headerA': 'valueA', - 'headerB': 'valueB'} - - self.cert = '/path/to/cert' - self.connection_params = {'cert': self.cert, 'verify': False} - - def url(self, prefix): - return '%s/%s' % (self.endpoint, prefix) - - def get_token(self, session, **kwargs): - # NOTE(jamielennox): by specifying get_headers this should not be used - return self.BAD_TOKEN - - def get_headers(self, session, **kwargs): - return self.headers - - def get_endpoint(self, session, **kwargs): - return self.endpoint - - def get_connection_params(self, session, **kwargs): - return self.connection_params - - -class GenericAuthPluginTests(utils.TestCase): - - # filter doesn't matter to GenericPlugin, but we have to specify one - ENDPOINT_FILTER = {uuid.uuid4().hex: uuid.uuid4().hex} - - def setUp(self): - super(GenericAuthPluginTests, self).setUp() - self.auth = GenericPlugin() - - with self.deprecations.expect_deprecations_here(): - self.session = session.Session(auth=self.auth) - - def test_setting_headers(self): - text = uuid.uuid4().hex - self.stub_url('GET', base_url=self.auth.url('prefix'), text=text) - - resp = self.session.get('prefix', endpoint_filter=self.ENDPOINT_FILTER) - - self.assertEqual(text, resp.text) - - for k, v in self.auth.headers.items(): - self.assertRequestHeaderEqual(k, v) - - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(self.session.get_token()) - self.assertEqual(self.auth.headers, - self.session.get_auth_headers()) - self.assertNotIn('X-Auth-Token', - self.requests_mock.last_request.headers) - - def test_setting_connection_params(self): - text = uuid.uuid4().hex - - with mock.patch.object(self.session.session, 'request') as mocked: - mocked.return_value = utils.test_response(text=text) - resp = self.session.get('prefix', - endpoint_filter=self.ENDPOINT_FILTER) - - self.assertEqual(text, resp.text) - - # the cert and verify values passed to request are those that were - # returned from the auth plugin as connection params. - - mocked.assert_called_once_with('GET', - self.auth.url('prefix'), - headers=mock.ANY, - allow_redirects=False, - cert=self.auth.cert, - verify=False) - - def test_setting_bad_connection_params(self): - # The uuid name parameter here is unknown and not in the allowed params - # to be returned to the session and so an error will be raised. - name = uuid.uuid4().hex - self.auth.connection_params[name] = uuid.uuid4().hex - - e = self.assertRaises(exceptions.UnsupportedParameters, - self.session.get, - 'prefix', - endpoint_filter=self.ENDPOINT_FILTER) - - self.assertIn(name, str(e)) diff --git a/keystoneclient/tests/unit/auth/test_identity_v2.py b/keystoneclient/tests/unit/auth/test_identity_v2.py deleted file mode 100644 index 8ef87c43..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_v2.py +++ /dev/null @@ -1,328 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import copy -import uuid - -import mock - -from keystoneclient.auth.identity import v2 -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class V2IdentityPlugin(utils.TestCase): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v2.0') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v2.0') - - TEST_PASS = 'password' - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "adminURL": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:8774/v1.0", - "publicURL": "http://cdn.admin-nets.local:8774/v1.0/" - }], - "type": "nova_compat", - "name": "nova_compat" - }, { - "endpoints": [{ - "adminURL": "http://nova/novapi/admin", - "region": "RegionOne", - "internalURL": "http://nova/novapi/internal", - "publicURL": "http://nova/novapi/public" - }], - "type": "compute", - "name": "nova" - }, { - "endpoints": [{ - "adminURL": "http://glance/glanceapi/admin", - "region": "RegionOne", - "internalURL": "http://glance/glanceapi/internal", - "publicURL": "http://glance/glanceapi/public" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "adminURL": TEST_ADMIN_URL, - "region": "RegionOne", - "internalURL": "http://127.0.0.1:5000/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - }], - "type": "identity", - "name": "keystone" - }, { - "endpoints": [{ - "adminURL": "http://swift/swiftapi/admin", - "region": "RegionOne", - "internalURL": "http://swift/swiftapi/internal", - "publicURL": "http://swift/swiftapi/public" - }], - "type": "object-store", - "name": "swift" - }] - - def setUp(self): - super(V2IdentityPlugin, self).setUp() - self.deprecations.expect_deprecations() - self.TEST_RESPONSE_DICT = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10.000123Z", - "id": self.TEST_TOKEN, - "tenant": { - "id": self.TEST_TENANT_ID - }, - }, - "user": { - "id": self.TEST_USER - }, - "serviceCatalog": self.TEST_SERVICE_CATALOG, - }, - } - - def stub_auth(self, **kwargs): - self.stub_url('POST', ['tokens'], **kwargs) - - def test_authenticate_with_username_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - self.assertIsNone(a.user_id) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'username': self.TEST_USER, - 'password': self.TEST_PASS}}} - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_user_id_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, user_id=self.TEST_USER, - password=self.TEST_PASS) - self.assertIsNone(a.username) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'userId': self.TEST_USER, - 'password': self.TEST_PASS}}} - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_username_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, tenant_id=self.TEST_TENANT_ID) - self.assertIsNone(a.user_id) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'username': self.TEST_USER, - 'password': self.TEST_PASS}, - 'tenantId': self.TEST_TENANT_ID}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_user_id_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, user_id=self.TEST_USER, - password=self.TEST_PASS, tenant_id=self.TEST_TENANT_ID) - self.assertIsNone(a.username) - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'userId': self.TEST_USER, - 'password': self.TEST_PASS}, - 'tenantId': self.TEST_TENANT_ID}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_token(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Token(self.TEST_URL, 'foo') - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'token': {'id': 'foo'}}} - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('x-Auth-Token', 'foo') - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_trust_id(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, trust_id='trust') - s = session.Session(a) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'passwordCredentials': {'username': self.TEST_USER, - 'password': self.TEST_PASS}, - 'trust_id': 'trust'}} - - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def _do_service_url_test(self, base_url, endpoint_filter): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', ['path'], - base_url=base_url, - text='SUCCESS', status_code=200) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter=endpoint_filter) - - self.assertEqual(resp.status_code, 200) - self.assertEqual(self.requests_mock.last_request.url, - base_url + '/path') - - def test_service_url(self): - endpoint_filter = {'service_type': 'compute', - 'interface': 'admin', - 'service_name': 'nova'} - self._do_service_url_test('http://nova/novapi/admin', endpoint_filter) - - def test_service_url_defaults_to_public(self): - endpoint_filter = {'service_type': 'compute'} - self._do_service_url_test('http://nova/novapi/public', endpoint_filter) - - def test_endpoint_filter_without_service_type_fails(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.EndpointNotFound, s.get, '/path', - endpoint_filter={'interface': 'admin'}) - - def test_full_url_overrides_endpoint_filter(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [], - base_url='http://testurl/', - text='SUCCESS', status_code=200) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('http://testurl/', - endpoint_filter={'service_type': 'compute'}) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.text, 'SUCCESS') - - def test_invalid_auth_response_dict(self): - self.stub_auth(json={'hello': 'world'}) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalid_auth_response_type(self): - self.stub_url('POST', ['tokens'], text='testdata') - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalidate_response(self): - resp_data1 = copy.deepcopy(self.TEST_RESPONSE_DICT) - resp_data2 = copy.deepcopy(self.TEST_RESPONSE_DICT) - - resp_data1['access']['token']['id'] = 'token1' - resp_data2['access']['token']['id'] = 'token2' - - auth_responses = [{'json': resp_data1}, {'json': resp_data2}] - self.stub_auth(response_list=auth_responses) - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token1', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token1'}, s.get_auth_headers()) - - a.invalidate() - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token2', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token2'}, s.get_auth_headers()) - - def test_doesnt_log_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - password = uuid.uuid4().hex - - a = v2.Password(self.TEST_URL, username=self.TEST_USER, - password=password) - s = session.Session(auth=a) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(self.TEST_TOKEN, s.get_token()) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - self.assertNotIn(password, self.logger.output) - - def test_password_with_no_user_id_or_name(self): - self.assertRaises(TypeError, - v2.Password, self.TEST_URL, password=self.TEST_PASS) - - @mock.patch('sys.stdin', autospec=True) - def test_prompt_password(self, mock_stdin): - parser = argparse.ArgumentParser() - v2.Password.register_argparse_arguments(parser) - - username = uuid.uuid4().hex - auth_url = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - password = uuid.uuid4().hex - - opts = parser.parse_args(['--os-username', username, - '--os-auth-url', auth_url, - '--os-tenant-id', tenant_id]) - - with mock.patch('getpass.getpass') as mock_getpass: - mock_getpass.return_value = password - mock_stdin.isatty = lambda: True - - plugin = v2.Password.load_from_argparse_arguments(opts) - - self.assertEqual(auth_url, plugin.auth_url) - self.assertEqual(username, plugin.username) - self.assertEqual(tenant_id, plugin.tenant_id) - self.assertEqual(password, plugin.password) diff --git a/keystoneclient/tests/unit/auth/test_identity_v3.py b/keystoneclient/tests/unit/auth/test_identity_v3.py deleted file mode 100644 index 534e9974..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_v3.py +++ /dev/null @@ -1,570 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import copy -import uuid - -from keystoneauth1 import fixture -import mock - -from keystoneclient import access -from keystoneclient.auth.identity import v3 -from keystoneclient.auth.identity.v3 import base as v3_base -from keystoneclient import client -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class V3IdentityPlugin(utils.TestCase): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v3') - - TEST_PASS = 'password' - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "url": "http://cdn.admin-nets.local:8774/v1.0/", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:8774/v1.0", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "interface": "admin" - }], - "type": "nova_compat" - }, { - "endpoints": [{ - "url": "http://nova/novapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://nova/novapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://nova/novapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "compute", - "name": "nova", - }, { - "endpoints": [{ - "url": "http://glance/glanceapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://glance/glanceapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://glance/glanceapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "internal" - }, { - "url": TEST_ADMIN_URL, - "region": "RegionOne", - "interface": "admin" - }], - "type": "identity" - }, { - "endpoints": [{ - "url": "http://swift/swiftapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://swift/swiftapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://swift/swiftapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "object-store" - }] - - def setUp(self): - super(V3IdentityPlugin, self).setUp() - - self.TEST_DISCOVERY_RESPONSE = { - 'versions': {'values': [fixture.V3Discovery(self.TEST_URL)]}} - - self.deprecations.expect_deprecations() - - self.TEST_RESPONSE_DICT = { - "token": { - "methods": [ - "token", - "password" - ], - - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_TENANT_ID, - "name": self.TEST_TENANT_NAME - }, - "user": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_USER, - "name": self.TEST_USER - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": self.TEST_SERVICE_CATALOG - }, - } - self.TEST_PROJECTS_RESPONSE = { - "projects": [ - { - "domain_id": "1789d1", - "enabled": "True", - "id": "263fd9", - "links": { - "self": "https://identity:5000/v3/projects/263fd9" - }, - "name": "Dev Group A" - }, - { - "domain_id": "1789d1", - "enabled": "True", - "id": "e56ad3", - "links": { - "self": "https://identity:5000/v3/projects/e56ad3" - }, - "name": "Dev Group B" - } - ], - "links": { - "self": "https://identity:5000/v3/projects", - } - } - - def stub_auth(self, subject_token=None, **kwargs): - if not subject_token: - subject_token = self.TEST_TOKEN - - self.stub_url('POST', ['auth', 'tokens'], - headers={'X-Subject-Token': subject_token}, **kwargs) - - def test_authenticate_with_username_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}}} - - self.assertRequestBodyIs(json=req) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_username_password_unscoped(self): - del self.TEST_RESPONSE_DICT['token']['catalog'] - del self.TEST_RESPONSE_DICT['token']['project'] - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url(method="GET", json=self.TEST_DISCOVERY_RESPONSE) - test_user_id = self.TEST_RESPONSE_DICT['token']['user']['id'] - self.stub_url(method="GET", - json=self.TEST_PROJECTS_RESPONSE, - parts=['users', test_user_id, 'projects']) - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - cs = client.Client(session=s) - - # As a sanity check on the auth_ref, make sure client has the - # proper user id, that it fetches the right project response - self.assertEqual(test_user_id, a.auth_ref.user_id) - t = cs.projects.list(user=a.auth_ref.user_id) - self.assertEqual(2, len(t)) - - def test_authenticate_with_username_password_domain_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, domain_id=self.TEST_DOMAIN_ID) - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}, - 'scope': {'domain': {'id': self.TEST_DOMAIN_ID}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_authenticate_with_username_password_project_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, - project_id=self.TEST_TENANT_ID) - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}, - 'scope': {'project': {'id': self.TEST_TENANT_ID}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - self.assertEqual(s.auth.auth_ref.project_id, self.TEST_TENANT_ID) - - def test_authenticate_with_token(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['token'], - 'token': {'id': self.TEST_TOKEN}}}} - - self.assertRequestBodyIs(json=req) - - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('Accept', 'application/json') - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_expired(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - d = copy.deepcopy(self.TEST_RESPONSE_DICT) - d['token']['expires_at'] = '2000-01-01T00:00:10.000123Z' - - a = v3.Password(self.TEST_URL, username='username', - password='password') - a.auth_ref = access.AccessInfo.factory(body=d) - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - self.assertEqual(a.auth_ref['expires_at'], - self.TEST_RESPONSE_DICT['token']['expires_at']) - - def test_with_domain_and_project_scoping(self): - a = v3.Password(self.TEST_URL, username='username', - password='password', project_id='project', - domain_id='domain') - - self.assertRaises(exceptions.AuthorizationFailure, - a.get_token, None) - self.assertRaises(exceptions.AuthorizationFailure, - a.get_headers, None) - - def test_with_trust_id(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS, trust_id='trust') - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}}, - 'scope': {'OS-TRUST:trust': {'id': 'trust'}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_multiple_mechanisms_factory(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - p = v3.PasswordMethod(username=self.TEST_USER, password=self.TEST_PASS) - t = v3.TokenMethod(token='foo') - a = v3.Auth(self.TEST_URL, [p, t], trust_id='trust') - s = session.Session(a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password', 'token'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}, - 'token': {'id': 'foo'}}, - 'scope': {'OS-TRUST:trust': {'id': 'trust'}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_multiple_mechanisms(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - p = v3.PasswordMethod(username=self.TEST_USER, - password=self.TEST_PASS) - t = v3.TokenMethod(token='foo') - a = v3.Auth(self.TEST_URL, [p, t], trust_id='trust') - s = session.Session(auth=a) - - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - req = {'auth': {'identity': - {'methods': ['password', 'token'], - 'password': {'user': {'name': self.TEST_USER, - 'password': self.TEST_PASS}}, - 'token': {'id': 'foo'}}, - 'scope': {'OS-TRUST:trust': {'id': 'trust'}}}} - self.assertRequestBodyIs(json=req) - self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - - def test_with_multiple_scopes(self): - s = session.Session() - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, password=self.TEST_PASS, - domain_id='x', project_id='x') - self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s) - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, password=self.TEST_PASS, - domain_id='x', trust_id='x') - self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s) - - def _do_service_url_test(self, base_url, endpoint_filter): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', ['path'], - base_url=base_url, - text='SUCCESS', status_code=200) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('/path', endpoint_filter=endpoint_filter) - - self.assertEqual(resp.status_code, 200) - self.assertEqual(self.requests_mock.last_request.url, - base_url + '/path') - - def test_service_url(self): - endpoint_filter = {'service_type': 'compute', - 'interface': 'admin', - 'service_name': 'nova'} - self._do_service_url_test('http://nova/novapi/admin', endpoint_filter) - - def test_service_url_defaults_to_public(self): - endpoint_filter = {'service_type': 'compute'} - self._do_service_url_test('http://nova/novapi/public', endpoint_filter) - - def test_endpoint_filter_without_service_type_fails(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.EndpointNotFound, s.get, '/path', - endpoint_filter={'interface': 'admin'}) - - def test_full_url_overrides_endpoint_filter(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [], - base_url='http://testurl/', - text='SUCCESS', status_code=200) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - resp = s.get('http://testurl/', - endpoint_filter={'service_type': 'compute'}) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.text, 'SUCCESS') - - def test_invalid_auth_response_dict(self): - self.stub_auth(json={'hello': 'world'}) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalid_auth_response_type(self): - self.stub_url('POST', ['auth', 'tokens'], text='testdata') - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', - authenticated=True) - - def test_invalidate_response(self): - auth_responses = [{'status_code': 200, 'json': self.TEST_RESPONSE_DICT, - 'headers': {'X-Subject-Token': 'token1'}}, - {'status_code': 200, 'json': self.TEST_RESPONSE_DICT, - 'headers': {'X-Subject-Token': 'token2'}}] - - self.requests_mock.post('%s/auth/tokens' % self.TEST_URL, - auth_responses) - - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=self.TEST_PASS) - s = session.Session(auth=a) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token1', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token1'}, s.get_auth_headers()) - a.invalidate() - with self.deprecations.expect_deprecations_here(): - self.assertEqual('token2', s.get_token()) - self.assertEqual({'X-Auth-Token': 'token2'}, s.get_auth_headers()) - - def test_doesnt_log_password(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - password = uuid.uuid4().hex - a = v3.Password(self.TEST_URL, username=self.TEST_USER, - password=password) - s = session.Session(a) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(self.TEST_TOKEN, s.get_token()) - self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, - s.get_auth_headers()) - - self.assertNotIn(password, self.logger.output) - - def test_sends_nocatalog(self): - del self.TEST_RESPONSE_DICT['token']['catalog'] - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - a = v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS, - include_catalog=False) - s = session.Session(auth=a) - - s.get_auth_headers() - - auth_url = self.TEST_URL + '/auth/tokens' - self.assertEqual(auth_url, a.token_url) - self.assertEqual(auth_url + '?nocatalog', - self.requests_mock.last_request.url) - - def test_symbols(self): - self.assertIs(v3.AuthMethod, v3_base.AuthMethod) - self.assertIs(v3.AuthConstructor, v3_base.AuthConstructor) - self.assertIs(v3.Auth, v3_base.Auth) - - def test_unscoped_request(self): - token = fixture.V3Token() - self.stub_auth(json=token) - password = uuid.uuid4().hex - - a = v3.Password(self.TEST_URL, - user_id=token.user_id, - password=password, - unscoped=True) - s = session.Session() - - auth_ref = a.get_access(s) - - with self.deprecations.expect_deprecations_here(): - self.assertFalse(auth_ref.scoped) - body = self.requests_mock.last_request.json() - - ident = body['auth']['identity'] - - self.assertEqual(['password'], ident['methods']) - self.assertEqual(token.user_id, ident['password']['user']['id']) - self.assertEqual(password, ident['password']['user']['password']) - - self.assertEqual({}, body['auth']['scope']['unscoped']) - - def test_unscoped_with_scope_data(self): - a = v3.Password(self.TEST_URL, - user_id=uuid.uuid4().hex, - password=uuid.uuid4().hex, - unscoped=True, - project_id=uuid.uuid4().hex) - - s = session.Session() - - self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s) - - @mock.patch('sys.stdin', autospec=True) - def test_prompt_password(self, mock_stdin): - parser = argparse.ArgumentParser() - v3.Password.register_argparse_arguments(parser) - - username = uuid.uuid4().hex - user_domain_id = uuid.uuid4().hex - auth_url = uuid.uuid4().hex - project_id = uuid.uuid4().hex - password = uuid.uuid4().hex - - opts = parser.parse_args(['--os-username', username, - '--os-auth-url', auth_url, - '--os-user-domain-id', user_domain_id, - '--os-project-id', project_id]) - - with mock.patch('getpass.getpass') as mock_getpass: - mock_getpass.return_value = password - mock_stdin.isatty = lambda: True - - plugin = v3.Password.load_from_argparse_arguments(opts) - - self.assertEqual(auth_url, plugin.auth_url) - self.assertEqual(username, plugin.auth_methods[0].username) - self.assertEqual(project_id, plugin.project_id) - self.assertEqual(user_domain_id, - plugin.auth_methods[0].user_domain_id) - self.assertEqual(password, plugin.auth_methods[0].password) diff --git a/keystoneclient/tests/unit/auth/test_identity_v3_federated.py b/keystoneclient/tests/unit/auth/test_identity_v3_federated.py deleted file mode 100644 index 7cbb5ab1..00000000 --- a/keystoneclient/tests/unit/auth/test_identity_v3_federated.py +++ /dev/null @@ -1,99 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import uuid - -from keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient.auth.identity import v3 -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class TesterFederationPlugin(v3.FederatedBaseAuth): - - def get_unscoped_auth_ref(self, sess, **kwargs): - # This would go and talk to an idp or something - resp = sess.post(self.federated_token_url, authenticated=False) - return access.AccessInfo.factory(resp=resp, body=resp.json()) - - -class V3FederatedPlugin(utils.TestCase): - - AUTH_URL = 'http://keystone/v3' - - def setUp(self): - super(V3FederatedPlugin, self).setUp() - - self.deprecations.expect_deprecations() - - self.unscoped_token = fixture.V3Token() - self.unscoped_token_id = uuid.uuid4().hex - self.scoped_token = copy.deepcopy(self.unscoped_token) - self.scoped_token.set_project_scope() - self.scoped_token.methods.append('token') - self.scoped_token_id = uuid.uuid4().hex - - s = self.scoped_token.add_service('compute', name='nova') - s.add_standard_endpoints(public='http://nova/public', - admin='http://nova/admin', - internal='http://nova/internal') - - self.idp = uuid.uuid4().hex - self.protocol = uuid.uuid4().hex - - self.token_url = ('%s/OS-FEDERATION/identity_providers/%s/protocols/%s' - '/auth' % (self.AUTH_URL, self.idp, self.protocol)) - - headers = {'X-Subject-Token': self.unscoped_token_id} - self.unscoped_mock = self.requests_mock.post(self.token_url, - json=self.unscoped_token, - headers=headers) - - headers = {'X-Subject-Token': self.scoped_token_id} - auth_url = self.AUTH_URL + '/auth/tokens' - self.scoped_mock = self.requests_mock.post(auth_url, - json=self.scoped_token, - headers=headers) - - def get_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.AUTH_URL) - kwargs.setdefault('protocol', self.protocol) - kwargs.setdefault('identity_provider', self.idp) - return TesterFederationPlugin(**kwargs) - - def test_federated_url(self): - plugin = self.get_plugin() - self.assertEqual(self.token_url, plugin.federated_token_url) - - def test_unscoped_behaviour(self): - sess = session.Session(auth=self.get_plugin()) - self.assertEqual(self.unscoped_token_id, sess.get_token()) - - self.assertTrue(self.unscoped_mock.called) - self.assertFalse(self.scoped_mock.called) - - def test_scoped_behaviour(self): - auth = self.get_plugin(project_id=self.scoped_token.project_id) - sess = session.Session(auth=auth) - self.assertEqual(self.scoped_token_id, sess.get_token()) - - self.assertTrue(self.unscoped_mock.called) - self.assertTrue(self.scoped_mock.called) - - def test_options(self): - opts = [o.name for o in v3.FederatedBaseAuth.get_options()] - - self.assertIn('protocol', opts) - self.assertIn('identity-provider', opts) diff --git a/keystoneclient/tests/unit/auth/test_loading.py b/keystoneclient/tests/unit/auth/test_loading.py deleted file mode 100644 index 3c2689dd..00000000 --- a/keystoneclient/tests/unit/auth/test_loading.py +++ /dev/null @@ -1,46 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - - -from keystoneclient.tests.unit.auth import utils - - -class TestOtherLoading(utils.TestCase): - - def test_loading_getter(self): - - called_opts = [] - - vals = {'a-int': 44, - 'a-bool': False, - 'a-float': 99.99, - 'a-str': 'value'} - - val = uuid.uuid4().hex - - def _getter(opt): - called_opts.append(opt.name) - # return str because oslo.config should convert them back - return str(vals[opt.name]) - - p = utils.MockPlugin.load_from_options_getter(_getter, other=val) - - self.assertEqual(set(vals), set(called_opts)) - - for k, v in vals.items(): - # replace - to _ because it's the dest used to create kwargs - self.assertEqual(v, p[k.replace('-', '_')]) - - # check that additional kwargs get passed through - self.assertEqual(val, p['other']) diff --git a/keystoneclient/tests/unit/auth/test_password.py b/keystoneclient/tests/unit/auth/test_password.py deleted file mode 100644 index 020eb124..00000000 --- a/keystoneclient/tests/unit/auth/test_password.py +++ /dev/null @@ -1,99 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import uuid - -import mock - -from keystoneclient.auth.identity.generic import password -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 -from keystoneclient.auth.identity.v3 import password as v3_password -from keystoneclient.tests.unit.auth import utils - - -class PasswordTests(utils.GenericPluginTestCase): - - PLUGIN_CLASS = password.Password - V2_PLUGIN_CLASS = v2.Password - V3_PLUGIN_CLASS = v3.Password - - def new_plugin(self, **kwargs): - kwargs.setdefault('username', uuid.uuid4().hex) - kwargs.setdefault('password', uuid.uuid4().hex) - return super(PasswordTests, self).new_plugin(**kwargs) - - def test_with_user_domain_params(self): - self.stub_discovery() - - self.assertCreateV3(domain_id=uuid.uuid4().hex, - user_domain_id=uuid.uuid4().hex) - - def test_v3_user_params_v2_url(self): - self.stub_discovery(v3=False) - self.assertDiscoveryFailure(user_domain_id=uuid.uuid4().hex) - - def test_options(self): - opts = [o.name for o in self.PLUGIN_CLASS.get_options()] - - allowed_opts = ['username', - 'user-domain-id', - 'user-domain-name', - 'user-id', - 'password', - - 'domain-id', - 'domain-name', - 'tenant-id', - 'tenant-name', - 'project-id', - 'project-name', - 'project-domain-id', - 'project-domain-name', - 'trust-id', - 'auth-url'] - - self.assertEqual(set(allowed_opts), set(opts)) - self.assertEqual(len(allowed_opts), len(opts)) - - def test_symbols(self): - self.assertIs(v3.Password, v3_password.Password) - self.assertIs(v3.PasswordMethod, v3_password.PasswordMethod) - - @mock.patch('sys.stdin', autospec=True) - def test_prompt_password(self, mock_stdin): - parser = argparse.ArgumentParser() - self.PLUGIN_CLASS.register_argparse_arguments(parser) - - username = uuid.uuid4().hex - user_domain_id = uuid.uuid4().hex - auth_url = uuid.uuid4().hex - project_id = uuid.uuid4().hex - password = uuid.uuid4().hex - - opts = parser.parse_args(['--os-username', username, - '--os-auth-url', auth_url, - '--os-user-domain-id', user_domain_id, - '--os-project-id', project_id]) - - with mock.patch('getpass.getpass') as mock_getpass: - mock_getpass.return_value = password - mock_stdin.isatty = lambda: True - - plugin = self.PLUGIN_CLASS.load_from_argparse_arguments(opts) - - self.assertEqual(auth_url, plugin.auth_url) - self.assertEqual(username, plugin._username) - self.assertEqual(project_id, plugin._project_id) - self.assertEqual(user_domain_id, plugin._user_domain_id) - self.assertEqual(password, plugin._password) diff --git a/keystoneclient/tests/unit/auth/test_token.py b/keystoneclient/tests/unit/auth/test_token.py deleted file mode 100644 index ce4c1cdc..00000000 --- a/keystoneclient/tests/unit/auth/test_token.py +++ /dev/null @@ -1,52 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.auth.identity.generic import token -from keystoneclient.auth.identity import v2 -from keystoneclient.auth.identity import v3 -from keystoneclient.auth.identity.v3 import token as v3_token -from keystoneclient.tests.unit.auth import utils - - -class TokenTests(utils.GenericPluginTestCase): - - PLUGIN_CLASS = token.Token - V2_PLUGIN_CLASS = v2.Token - V3_PLUGIN_CLASS = v3.Token - - def new_plugin(self, **kwargs): - kwargs.setdefault('token', uuid.uuid4().hex) - return super(TokenTests, self).new_plugin(**kwargs) - - def test_options(self): - opts = [o.name for o in self.PLUGIN_CLASS.get_options()] - - allowed_opts = ['token', - 'domain-id', - 'domain-name', - 'tenant-id', - 'tenant-name', - 'project-id', - 'project-name', - 'project-domain-id', - 'project-domain-name', - 'trust-id', - 'auth-url'] - - self.assertEqual(set(allowed_opts), set(opts)) - self.assertEqual(len(allowed_opts), len(opts)) - - def test_symbols(self): - self.assertIs(v3.Token, v3_token.Token) - self.assertIs(v3.TokenMethod, v3_token.TokenMethod) diff --git a/keystoneclient/tests/unit/auth/test_token_endpoint.py b/keystoneclient/tests/unit/auth/test_token_endpoint.py deleted file mode 100644 index 9a9a1ed9..00000000 --- a/keystoneclient/tests/unit/auth/test_token_endpoint.py +++ /dev/null @@ -1,67 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from testtools import matchers - -from keystoneclient.auth import token_endpoint -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class TokenEndpointTest(utils.TestCase): - - TEST_TOKEN = 'aToken' - TEST_URL = 'http://server/prefix' - - def setUp(self): - super(TokenEndpointTest, self).setUp() - self.deprecations.expect_deprecations() - - def test_basic_case(self): - self.requests_mock.get(self.TEST_URL, text='body') - - a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session(auth=a) - - data = s.get(self.TEST_URL, authenticated=True) - - self.assertEqual(data.text, 'body') - self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) - - def test_basic_endpoint_case(self): - self.stub_url('GET', ['p'], text='body') - a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session(auth=a) - - data = s.get('/p', - authenticated=True, - endpoint_filter={'service': 'identity'}) - - self.assertEqual(self.TEST_URL, a.get_endpoint(s)) - self.assertEqual('body', data.text) - self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) - - def test_token_endpoint_options(self): - opt_names = [opt.name for opt in token_endpoint.Token.get_options()] - - self.assertThat(opt_names, matchers.HasLength(2)) - - self.assertIn('token', opt_names) - self.assertIn('endpoint', opt_names) - - def test_token_endpoint_user_id(self): - a = token_endpoint.Token(self.TEST_URL, self.TEST_TOKEN) - s = session.Session() - - # we can't know this information about this sort of plugin - self.assertIsNone(a.get_user_id(s)) - self.assertIsNone(a.get_project_id(s)) diff --git a/keystoneclient/tests/unit/auth/utils.py b/keystoneclient/tests/unit/auth/utils.py deleted file mode 100644 index b6931728..00000000 --- a/keystoneclient/tests/unit/auth/utils.py +++ /dev/null @@ -1,202 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import functools -import uuid - -from keystoneauth1 import fixture -import mock -from oslo_config import cfg - -from keystoneclient import access -from keystoneclient.auth import base -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -class MockPlugin(base.BaseAuthPlugin): - - INT_DESC = 'test int' - FLOAT_DESC = 'test float' - BOOL_DESC = 'test bool' - STR_DESC = 'test str' - STR_DEFAULT = uuid.uuid4().hex - - def __init__(self, **kwargs): - self._data = kwargs - - def __getitem__(self, key): - """Get the data of the key.""" - return self._data[key] - - def get_token(self, *args, **kwargs): - return 'aToken' - - def get_endpoint(self, *args, **kwargs): - return 'http://test' - - @classmethod - def get_options(cls): - return [ - cfg.IntOpt('a-int', default='3', help=cls.INT_DESC), - cfg.BoolOpt('a-bool', help=cls.BOOL_DESC), - cfg.FloatOpt('a-float', help=cls.FLOAT_DESC), - cfg.StrOpt('a-str', help=cls.STR_DESC, default=cls.STR_DEFAULT), - ] - - -class MockManager(object): - - def __init__(self, driver): - self.driver = driver - - -def mock_plugin(f): - @functools.wraps(f) - def inner(*args, **kwargs): - with mock.patch.object(base, 'get_plugin_class') as m: - m.return_value = MockPlugin - args = list(args) + [m] - return f(*args, **kwargs) - - return inner - - -class TestCase(utils.TestCase): - - GROUP = 'auth' - V2PASS = 'v2password' - V3TOKEN = 'v3token' - - a_int = 88 - a_float = 88.8 - a_bool = False - - TEST_VALS = {'a_int': a_int, - 'a_float': a_float, - 'a_bool': a_bool} - - def assertTestVals(self, plugin, vals=TEST_VALS): - for k, v in vals.items(): - self.assertEqual(v, plugin[k]) - - -class GenericPluginTestCase(utils.TestCase): - - TEST_URL = 'http://keystone.host:5000/' - - # OVERRIDE THESE IN SUB CLASSES - PLUGIN_CLASS = None - V2_PLUGIN_CLASS = None - V3_PLUGIN_CLASS = None - - def setUp(self): - super(GenericPluginTestCase, self).setUp() - - self.token_v2 = fixture.V2Token() - self.token_v3 = fixture.V3Token() - self.token_v3_id = uuid.uuid4().hex - - self.deprecations.expect_deprecations() - self.session = session.Session() - - self.stub_url('POST', ['v2.0', 'tokens'], json=self.token_v2) - self.stub_url('POST', ['v3', 'auth', 'tokens'], - headers={'X-Subject-Token': self.token_v3_id}, - json=self.token_v3) - - def new_plugin(self, **kwargs): - kwargs.setdefault('auth_url', self.TEST_URL) - return self.PLUGIN_CLASS(**kwargs) - - def stub_discovery(self, base_url=None, **kwargs): - kwargs.setdefault('href', self.TEST_URL) - disc = fixture.DiscoveryList(**kwargs) - self.stub_url('GET', json=disc, base_url=base_url, status_code=300) - return disc - - def assertCreateV3(self, **kwargs): - auth = self.new_plugin(**kwargs) - auth_ref = auth.get_auth_ref(self.session) - self.assertIsInstance(auth_ref, access.AccessInfoV3) - self.assertEqual(self.TEST_URL + 'v3/auth/tokens', - self.requests_mock.last_request.url) - self.assertIsInstance(auth._plugin, self.V3_PLUGIN_CLASS) - return auth - - def assertCreateV2(self, **kwargs): - auth = self.new_plugin(**kwargs) - auth_ref = auth.get_auth_ref(self.session) - self.assertIsInstance(auth_ref, access.AccessInfoV2) - self.assertEqual(self.TEST_URL + 'v2.0/tokens', - self.requests_mock.last_request.url) - self.assertIsInstance(auth._plugin, self.V2_PLUGIN_CLASS) - return auth - - def assertDiscoveryFailure(self, **kwargs): - plugin = self.new_plugin(**kwargs) - self.assertRaises(exceptions.DiscoveryFailure, - plugin.get_auth_ref, - self.session) - - def test_create_v3_if_domain_params(self): - self.stub_discovery() - - self.assertCreateV3(domain_id=uuid.uuid4().hex) - self.assertCreateV3(domain_name=uuid.uuid4().hex) - self.assertCreateV3(project_name=uuid.uuid4().hex, - project_domain_name=uuid.uuid4().hex) - self.assertCreateV3(project_name=uuid.uuid4().hex, - project_domain_id=uuid.uuid4().hex) - - def test_create_v2_if_no_domain_params(self): - self.stub_discovery() - self.assertCreateV2() - self.assertCreateV2(project_id=uuid.uuid4().hex) - self.assertCreateV2(project_name=uuid.uuid4().hex) - self.assertCreateV2(tenant_id=uuid.uuid4().hex) - self.assertCreateV2(tenant_name=uuid.uuid4().hex) - - def test_v3_params_v2_url(self): - self.stub_discovery(v3=False) - self.assertDiscoveryFailure(domain_name=uuid.uuid4().hex) - - def test_v2_params_v3_url(self): - self.stub_discovery(v2=False) - self.assertCreateV3() - - def test_no_urls(self): - self.stub_discovery(v2=False, v3=False) - self.assertDiscoveryFailure() - - def test_path_based_url_v2(self): - self.stub_url('GET', ['v2.0'], status_code=403) - self.assertCreateV2(auth_url=self.TEST_URL + 'v2.0') - - def test_path_based_url_v3(self): - self.stub_url('GET', ['v3'], status_code=403) - self.assertCreateV3(auth_url=self.TEST_URL + 'v3') - - def test_disc_error_for_failure(self): - self.stub_url('GET', [], status_code=403) - self.assertDiscoveryFailure() - - def test_v3_plugin_from_failure(self): - url = self.TEST_URL + 'v3' - self.stub_url('GET', [], base_url=url, status_code=403) - self.assertCreateV3(auth_url=url) - - def test_unknown_discovery_version(self): - # make a v4 entry that's mostly the same as a v3 - self.stub_discovery(v2=False, v3_id='v4.0') - self.assertDiscoveryFailure() diff --git a/keystoneclient/tests/unit/client_fixtures.py b/keystoneclient/tests/unit/client_fixtures.py deleted file mode 100644 index 6da259c9..00000000 --- a/keystoneclient/tests/unit/client_fixtures.py +++ /dev/null @@ -1,744 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import contextlib -import os -import uuid -import warnings - -import fixtures -from keystoneauth1 import fixture -from keystoneauth1 import identity as ksa_identity -from keystoneauth1 import session as ksa_session -from oslo_serialization import jsonutils -from oslo_utils import timeutils -import six -import testresources - -from keystoneclient.auth import identity as ksc_identity -from keystoneclient.common import cms -from keystoneclient import session as ksc_session -from keystoneclient import utils -from keystoneclient.v2_0 import client as v2_client -from keystoneclient.v3 import client as v3_client - - -TEST_ROOT_URL = 'http://127.0.0.1:5000/' - -TESTDIR = os.path.dirname(os.path.abspath(__file__)) -ROOTDIR = os.path.normpath(os.path.join(TESTDIR, '..', '..', '..')) -CERTDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'certs') -CMSDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'cms') -KEYDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'private') - - -class BaseFixture(fixtures.Fixture): - - TEST_ROOT_URL = TEST_ROOT_URL - - def __init__(self, requests, deprecations): - super(BaseFixture, self).__init__() - self.requests = requests - self.deprecations = deprecations - self.user_id = uuid.uuid4().hex - self.client = self.new_client() - - -class BaseV2(BaseFixture): - - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v2.0') - - -class OriginalV2(BaseV2): - - def new_client(self): - # Creating a Client not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - return v2_client.Client(username=uuid.uuid4().hex, - user_id=self.user_id, - token=uuid.uuid4().hex, - tenant_name=uuid.uuid4().hex, - auth_url=self.TEST_URL, - endpoint=self.TEST_URL) - - -class KscSessionV2(BaseV2): - - def new_client(self): - t = fixture.V2Token(user_id=self.user_id) - t.set_scope() - - s = t.add_service('identity') - s.add_endpoint(self.TEST_URL) - - d = fixture.V2Discovery(self.TEST_URL) - - self.requests.register_uri('POST', self.TEST_URL + '/tokens', json=t) - - # NOTE(jamielennox): Because of the versioned URL hack here even though - # the V2 URL will be in the service catalog it will be the root URL - # that will be queried for discovery. - self.requests.register_uri('GET', self.TEST_ROOT_URL, - json={'version': d}) - - with self.deprecations.expect_deprecations_here(): - a = ksc_identity.V2Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - auth_url=self.TEST_URL) - - s = ksc_session.Session(auth=a) - - return v2_client.Client(session=s) - - -class KsaSessionV2(BaseV2): - - def new_client(self): - t = fixture.V2Token(user_id=self.user_id) - t.set_scope() - - s = t.add_service('identity') - s.add_endpoint(self.TEST_URL) - - d = fixture.V2Discovery(self.TEST_URL) - - self.requests.register_uri('POST', self.TEST_URL + '/tokens', json=t) - - # NOTE(jamielennox): Because of the versioned URL hack here even though - # the V2 URL will be in the service catalog it will be the root URL - # that will be queried for discovery. - self.requests.register_uri('GET', self.TEST_ROOT_URL, - json={'version': d}) - - a = ksa_identity.V2Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - auth_url=self.TEST_URL) - s = ksa_session.Session(auth=a) - return v2_client.Client(session=s) - - -class BaseV3(BaseFixture): - - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - - -class OriginalV3(BaseV3): - - def new_client(self): - # Creating a Client not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - return v3_client.Client(username=uuid.uuid4().hex, - user_id=self.user_id, - token=uuid.uuid4().hex, - tenant_name=uuid.uuid4().hex, - auth_url=self.TEST_URL, - endpoint=self.TEST_URL) - - -class KscSessionV3(BaseV3): - - def new_client(self): - t = fixture.V3Token(user_id=self.user_id) - t.set_project_scope() - - s = t.add_service('identity') - s.add_standard_endpoints(public=self.TEST_URL, - admin=self.TEST_URL) - - d = fixture.V3Discovery(self.TEST_URL) - - headers = {'X-Subject-Token': uuid.uuid4().hex} - self.requests.register_uri('POST', - self.TEST_URL + '/auth/tokens', - headers=headers, - json=t) - self.requests.register_uri('GET', self.TEST_URL, json={'version': d}) - - with self.deprecations.expect_deprecations_here(): - a = ksc_identity.V3Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - user_domain_id=uuid.uuid4().hex, - auth_url=self.TEST_URL) - - s = ksc_session.Session(auth=a) - - return v3_client.Client(session=s) - - -class KsaSessionV3(BaseV3): - - def new_client(self): - t = fixture.V3Token(user_id=self.user_id) - t.set_project_scope() - - s = t.add_service('identity') - s.add_standard_endpoints(public=self.TEST_URL, - admin=self.TEST_URL) - - d = fixture.V3Discovery(self.TEST_URL) - - headers = {'X-Subject-Token': uuid.uuid4().hex} - self.requests.register_uri('POST', - self.TEST_URL + '/auth/tokens', - headers=headers, - json=t) - self.requests.register_uri('GET', self.TEST_URL, json={'version': d}) - - a = ksa_identity.V3Password(username=uuid.uuid4().hex, - password=uuid.uuid4().hex, - user_domain_id=uuid.uuid4().hex, - auth_url=self.TEST_URL) - s = ksa_session.Session(auth=a) - return v3_client.Client(session=s) - - -def _hash_signed_token_safe(signed_text, **kwargs): - if isinstance(signed_text, six.text_type): - signed_text = signed_text.encode('utf-8') - return utils.hash_signed_token(signed_text, **kwargs) - - -class Examples(fixtures.Fixture): - """Example tokens and certs loaded from the examples directory. - - To use this class correctly, the module needs to override the test suite - class to use testresources.OptimisingTestSuite (otherwise the files will - be read on every test). This is done by defining a load_tests function - in the module, like this: - - def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) - - (see http://docs.python.org/2/library/unittest.html#load-tests-protocol ) - - """ - - def setUp(self): - super(Examples, self).setUp() - - # The data for several tests are signed using openssl and are stored in - # files in the signing subdirectory. In order to keep the values - # consistent between the tests and the signed documents, we read them - # in for use in the tests. - with open(os.path.join(CMSDIR, 'auth_token_scoped.json')) as f: - self.TOKEN_SCOPED_DATA = cms.cms_to_token(f.read()) - - with open(os.path.join(CMSDIR, 'auth_token_scoped.pem')) as f: - self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read()) - self.SIGNED_TOKEN_SCOPED_HASH = _hash_signed_token_safe( - self.SIGNED_TOKEN_SCOPED) - self.SIGNED_TOKEN_SCOPED_HASH_SHA256 = _hash_signed_token_safe( - self.SIGNED_TOKEN_SCOPED, mode='sha256') - with open(os.path.join(CMSDIR, 'auth_token_unscoped.pem')) as f: - self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_scoped.pem')) as f: - self.SIGNED_v3_TOKEN_SCOPED = cms.cms_to_token(f.read()) - self.SIGNED_v3_TOKEN_SCOPED_HASH = _hash_signed_token_safe( - self.SIGNED_v3_TOKEN_SCOPED) - self.SIGNED_v3_TOKEN_SCOPED_HASH_SHA256 = _hash_signed_token_safe( - self.SIGNED_v3_TOKEN_SCOPED, mode='sha256') - with open(os.path.join(CMSDIR, 'auth_token_revoked.pem')) as f: - self.REVOKED_TOKEN = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_scoped_expired.pem')) as f: - self.SIGNED_TOKEN_SCOPED_EXPIRED = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_revoked.pem')) as f: - self.REVOKED_v3_TOKEN = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_scoped.pkiz')) as f: - self.SIGNED_TOKEN_SCOPED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_unscoped.pkiz')) as f: - self.SIGNED_TOKEN_UNSCOPED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_scoped.pkiz')) as f: - self.SIGNED_v3_TOKEN_SCOPED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_token_revoked.pkiz')) as f: - self.REVOKED_TOKEN_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, - 'auth_token_scoped_expired.pkiz')) as f: - self.SIGNED_TOKEN_SCOPED_EXPIRED_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'auth_v3_token_revoked.pkiz')) as f: - self.REVOKED_v3_TOKEN_PKIZ = cms.cms_to_token(f.read()) - with open(os.path.join(CMSDIR, 'revocation_list.json')) as f: - self.REVOCATION_LIST = jsonutils.loads(f.read()) - with open(os.path.join(CMSDIR, 'revocation_list.pem')) as f: - self.SIGNED_REVOCATION_LIST = jsonutils.dumps({'signed': f.read()}) - - self.SIGNING_CERT_FILE = os.path.join(CERTDIR, 'signing_cert.pem') - with open(self.SIGNING_CERT_FILE) as f: - self.SIGNING_CERT = f.read() - - self.KERBEROS_BIND = 'USER@REALM' - - self.SIGNING_KEY_FILE = os.path.join(KEYDIR, 'signing_key.pem') - with open(self.SIGNING_KEY_FILE) as f: - self.SIGNING_KEY = f.read() - - self.SIGNING_CA_FILE = os.path.join(CERTDIR, 'cacert.pem') - with open(self.SIGNING_CA_FILE) as f: - self.SIGNING_CA = f.read() - - self.UUID_TOKEN_DEFAULT = "ec6c0710ec2f471498484c1b53ab4f9d" - self.UUID_TOKEN_NO_SERVICE_CATALOG = '8286720fbe4941e69fa8241723bb02df' - self.UUID_TOKEN_UNSCOPED = '731f903721c14827be7b2dc912af7776' - self.UUID_TOKEN_BIND = '3fc54048ad64405c98225ce0897af7c5' - self.UUID_TOKEN_UNKNOWN_BIND = '8885fdf4d42e4fb9879e6379fa1eaf48' - self.VALID_DIABLO_TOKEN = 'b0cf19b55dbb4f20a6ee18e6c6cf1726' - self.v3_UUID_TOKEN_DEFAULT = '5603457654b346fdbb93437bfe76f2f1' - self.v3_UUID_TOKEN_UNSCOPED = 'd34835fdaec447e695a0a024d84f8d79' - self.v3_UUID_TOKEN_DOMAIN_SCOPED = 'e8a7b63aaa4449f38f0c5c05c3581792' - self.v3_UUID_TOKEN_BIND = '2f61f73e1c854cbb9534c487f9bd63c2' - self.v3_UUID_TOKEN_UNKNOWN_BIND = '7ed9781b62cd4880b8d8c6788ab1d1e2' - - revoked_token = self.REVOKED_TOKEN - if isinstance(revoked_token, six.text_type): - revoked_token = revoked_token.encode('utf-8') - self.REVOKED_TOKEN_HASH = utils.hash_signed_token(revoked_token) - self.REVOKED_TOKEN_HASH_SHA256 = utils.hash_signed_token(revoked_token, - mode='sha256') - self.REVOKED_TOKEN_LIST = ( - {'revoked': [{'id': self.REVOKED_TOKEN_HASH, - 'expires': timeutils.utcnow()}]}) - self.REVOKED_TOKEN_LIST_JSON = jsonutils.dumps(self.REVOKED_TOKEN_LIST) - - revoked_v3_token = self.REVOKED_v3_TOKEN - if isinstance(revoked_v3_token, six.text_type): - revoked_v3_token = revoked_v3_token.encode('utf-8') - self.REVOKED_v3_TOKEN_HASH = utils.hash_signed_token(revoked_v3_token) - hash = utils.hash_signed_token(revoked_v3_token, mode='sha256') - self.REVOKED_v3_TOKEN_HASH_SHA256 = hash - self.REVOKED_v3_TOKEN_LIST = ( - {'revoked': [{'id': self.REVOKED_v3_TOKEN_HASH, - 'expires': timeutils.utcnow()}]}) - self.REVOKED_v3_TOKEN_LIST_JSON = jsonutils.dumps( - self.REVOKED_v3_TOKEN_LIST) - - revoked_token_pkiz = self.REVOKED_TOKEN_PKIZ - if isinstance(revoked_token_pkiz, six.text_type): - revoked_token_pkiz = revoked_token_pkiz.encode('utf-8') - self.REVOKED_TOKEN_PKIZ_HASH = utils.hash_signed_token( - revoked_token_pkiz) - revoked_v3_token_pkiz = self.REVOKED_v3_TOKEN_PKIZ - if isinstance(revoked_v3_token_pkiz, six.text_type): - revoked_v3_token_pkiz = revoked_v3_token_pkiz.encode('utf-8') - self.REVOKED_v3_PKIZ_TOKEN_HASH = utils.hash_signed_token( - revoked_v3_token_pkiz) - - self.REVOKED_TOKEN_PKIZ_LIST = ( - {'revoked': [{'id': self.REVOKED_TOKEN_PKIZ_HASH, - 'expires': timeutils.utcnow()}, - {'id': self.REVOKED_v3_PKIZ_TOKEN_HASH, - 'expires': timeutils.utcnow()}, - ]}) - self.REVOKED_TOKEN_PKIZ_LIST_JSON = jsonutils.dumps( - self.REVOKED_TOKEN_PKIZ_LIST) - - self.SIGNED_TOKEN_SCOPED_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_SCOPED) - self.SIGNED_TOKEN_UNSCOPED_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_UNSCOPED) - self.SIGNED_v3_TOKEN_SCOPED_KEY = cms.cms_hash_token( - self.SIGNED_v3_TOKEN_SCOPED) - - self.SIGNED_TOKEN_SCOPED_PKIZ_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_SCOPED_PKIZ) - self.SIGNED_TOKEN_UNSCOPED_PKIZ_KEY = cms.cms_hash_token( - self.SIGNED_TOKEN_UNSCOPED_PKIZ) - self.SIGNED_v3_TOKEN_SCOPED_PKIZ_KEY = cms.cms_hash_token( - self.SIGNED_v3_TOKEN_SCOPED_PKIZ) - - self.INVALID_SIGNED_TOKEN = ( - "MIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" - "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "0000000000000000000000000000000000000000000000000000000000000000" - "1111111111111111111111111111111111111111111111111111111111111111" - "2222222222222222222222222222222222222222222222222222222222222222" - "3333333333333333333333333333333333333333333333333333333333333333" - "4444444444444444444444444444444444444444444444444444444444444444" - "5555555555555555555555555555555555555555555555555555555555555555" - "6666666666666666666666666666666666666666666666666666666666666666" - "7777777777777777777777777777777777777777777777777777777777777777" - "8888888888888888888888888888888888888888888888888888888888888888" - "9999999999999999999999999999999999999999999999999999999999999999" - "0000000000000000000000000000000000000000000000000000000000000000") - - self.INVALID_SIGNED_PKIZ_TOKEN = ( - "PKIZ_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" - "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" - "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "0000000000000000000000000000000000000000000000000000000000000000" - "1111111111111111111111111111111111111111111111111111111111111111" - "2222222222222222222222222222222222222222222222222222222222222222" - "3333333333333333333333333333333333333333333333333333333333333333" - "4444444444444444444444444444444444444444444444444444444444444444" - "5555555555555555555555555555555555555555555555555555555555555555" - "6666666666666666666666666666666666666666666666666666666666666666" - "7777777777777777777777777777777777777777777777777777777777777777" - "8888888888888888888888888888888888888888888888888888888888888888" - "9999999999999999999999999999999999999999999999999999999999999999" - "0000000000000000000000000000000000000000000000000000000000000000") - - # JSON responses keyed by token ID - self.TOKEN_RESPONSES = { - self.UUID_TOKEN_DEFAULT: { - 'access': { - 'token': { - 'id': self.UUID_TOKEN_DEFAULT, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - 'serviceCatalog': {} - }, - }, - self.VALID_DIABLO_TOKEN: { - 'access': { - 'token': { - 'id': self.VALID_DIABLO_TOKEN, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenantId': 'tenant_id1', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.UUID_TOKEN_UNSCOPED: { - 'access': { - 'token': { - 'id': self.UUID_TOKEN_UNSCOPED, - 'expires': '2020-01-01T00:00:10.000123Z', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.UUID_TOKEN_NO_SERVICE_CATALOG: { - 'access': { - 'token': { - 'id': 'valid-token', - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - } - }, - }, - self.UUID_TOKEN_BIND: { - 'access': { - 'token': { - 'bind': {'kerberos': self.KERBEROS_BIND}, - 'id': self.UUID_TOKEN_BIND, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - 'serviceCatalog': {} - }, - }, - self.UUID_TOKEN_UNKNOWN_BIND: { - 'access': { - 'token': { - 'bind': {'FOO': 'BAR'}, - 'id': self.UUID_TOKEN_UNKNOWN_BIND, - 'expires': '2020-01-01T00:00:10.000123Z', - 'tenant': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - }, - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - 'serviceCatalog': {} - }, - }, - self.v3_UUID_TOKEN_DEFAULT: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - self.v3_UUID_TOKEN_UNSCOPED: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - } - } - }, - self.v3_UUID_TOKEN_DOMAIN_SCOPED: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1', - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - self.SIGNED_TOKEN_SCOPED_KEY: { - 'access': { - 'token': { - 'id': self.SIGNED_TOKEN_SCOPED_KEY, - 'expires': '2020-01-01T00:00:10.000123Z', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'tenantId': 'tenant_id1', - 'tenantName': 'tenant_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.SIGNED_TOKEN_UNSCOPED_KEY: { - 'access': { - 'token': { - 'id': self.SIGNED_TOKEN_UNSCOPED_KEY, - 'expires': '2020-01-01T00:00:10.000123Z', - }, - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'}, - ], - }, - }, - }, - self.SIGNED_v3_TOKEN_SCOPED_KEY: { - 'token': { - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1'}, - {'name': 'role2'} - ], - 'catalog': {} - } - }, - self.v3_UUID_TOKEN_BIND: { - 'token': { - 'bind': {'kerberos': self.KERBEROS_BIND}, - 'methods': ['password'], - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - self.v3_UUID_TOKEN_UNKNOWN_BIND: { - 'token': { - 'bind': {'FOO': 'BAR'}, - 'expires_at': '2020-01-01T00:00:10.000123Z', - 'methods': ['password'], - 'user': { - 'id': 'user_id1', - 'name': 'user_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'project': { - 'id': 'tenant_id1', - 'name': 'tenant_name1', - 'domain': { - 'id': 'domain_id1', - 'name': 'domain_name1' - } - }, - 'roles': [ - {'name': 'role1', 'id': 'Role1'}, - {'name': 'role2', 'id': 'Role2'}, - ], - 'catalog': {} - } - }, - } - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_PKIZ_KEY] = ( - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_KEY]) - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_UNSCOPED_PKIZ_KEY] = ( - self.TOKEN_RESPONSES[self.SIGNED_TOKEN_UNSCOPED_KEY]) - self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_PKIZ_KEY] = ( - self.TOKEN_RESPONSES[self.SIGNED_v3_TOKEN_SCOPED_KEY]) - - self.JSON_TOKEN_RESPONSES = dict([(k, jsonutils.dumps(v)) for k, v in - self.TOKEN_RESPONSES.items()]) - - -EXAMPLES_RESOURCE = testresources.FixtureResource(Examples()) - - -class Deprecations(fixtures.Fixture): - def setUp(self): - super(Deprecations, self).setUp() - - # If keystoneclient calls any deprecated function this will raise an - # exception. - warnings.filterwarnings('error', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') - self.addCleanup(warnings.resetwarnings) - - def expect_deprecations(self): - """Call this if the test expects to call deprecated function.""" - warnings.resetwarnings() - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') - - @contextlib.contextmanager - def expect_deprecations_here(self): - warnings.resetwarnings() - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') - yield - warnings.resetwarnings() - warnings.filterwarnings('error', category=DeprecationWarning, - module='^keystoneclient\\.') - warnings.filterwarnings('ignore', category=DeprecationWarning, - module='^debtcollector\\.') diff --git a/keystoneclient/tests/unit/generic/__init__.py b/keystoneclient/tests/unit/generic/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/generic/test_client.py b/keystoneclient/tests/unit/generic/test_client.py deleted file mode 100644 index 5c27b6eb..00000000 --- a/keystoneclient/tests/unit/generic/test_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils - -from keystoneclient.generic import client -from keystoneclient.tests.unit import utils - -BASE_HOST = 'http://keystone.example.com' -BASE_URL = "%s:5000/" % BASE_HOST -V2_URL = "%sv2.0" % BASE_URL - -EXTENSION_NAMESPACE = ("https://docs.openstack.org/identity/api/ext/OS-FAKE/" - "v1.0") -EXTENSION_DESCRIBED = {"href": "https://github.com/openstack/identity-api", - "rel": "describedby", - "type": "text/html"} - -EXTENSION_ALIAS_FOO = "OS-FAKE-FOO" -EXTENSION_NAME_FOO = "OpenStack Keystone Fake Extension Foo" -EXTENSION_FOO = {"alias": EXTENSION_ALIAS_FOO, - "description": "Fake Foo extension to V2.0 API.", - "links": [EXTENSION_DESCRIBED], - "name": EXTENSION_NAME_FOO, - "namespace": EXTENSION_NAMESPACE, - "updated": '2014-01-08T00:00:00Z'} - -EXTENSION_ALIAS_BAR = "OS-FAKE-BAR" -EXTENSION_NAME_BAR = "OpenStack Keystone Fake Extension Bar" -EXTENSION_BAR = {"alias": EXTENSION_ALIAS_BAR, - "description": "Fake Bar extension to V2.0 API.", - "links": [EXTENSION_DESCRIBED], - "name": EXTENSION_NAME_BAR, - "namespace": EXTENSION_NAMESPACE, - "updated": '2014-01-08T00:00:00Z'} - - -def _create_extension_list(extensions): - return jsonutils.dumps({'extensions': {'values': extensions}}) - - -EXTENSION_LIST = _create_extension_list([EXTENSION_FOO, EXTENSION_BAR]) - - -class ClientDiscoveryTests(utils.TestCase): - - def test_discover_extensions_v2(self): - self.requests_mock.get("%s/extensions" % V2_URL, text=EXTENSION_LIST) - # Creating a HTTPClient not using session is deprecated. - # creating a generic client at all is deprecated. - with self.deprecations.expect_deprecations_here(): - extensions = client.Client().discover_extensions(url=V2_URL) - self.assertIn(EXTENSION_ALIAS_FOO, extensions) - self.assertEqual(extensions[EXTENSION_ALIAS_FOO], EXTENSION_NAME_FOO) - self.assertIn(EXTENSION_ALIAS_BAR, extensions) - self.assertEqual(extensions[EXTENSION_ALIAS_BAR], EXTENSION_NAME_BAR) diff --git a/keystoneclient/tests/unit/test_base.py b/keystoneclient/tests/unit/test_base.py deleted file mode 100644 index 0a0fde1c..00000000 --- a/keystoneclient/tests/unit/test_base.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from keystoneauth1.identity import v2 -from keystoneauth1 import session - -from keystoneclient import base -from keystoneclient.tests.unit import utils -from keystoneclient.v2_0 import client -from keystoneclient.v2_0 import roles - - -class HumanReadable(base.Resource): - HUMAN_ID = True - - -class BaseTest(utils.TestCase): - - def test_resource_repr(self): - r = base.Resource(None, dict(foo="bar", baz="spam")) - self.assertEqual(repr(r), "") - - def test_getid(self): - self.assertEqual(base.getid(4), 4) - - class TmpObject(object): - id = 4 - self.assertEqual(base.getid(TmpObject), 4) - - def test_resource_lazy_getattr(self): - auth = v2.Token(token=self.TEST_TOKEN, - auth_url='http://127.0.0.1:5000') - session_ = session.Session(auth=auth) - self.client = client.Client(session=session_) - - self.useFixture(fixtures.MockPatchObject( - self.client._adapter, 'get', side_effect=AttributeError, - autospec=True)) - - f = roles.Role(self.client.roles, {'id': 1, 'name': 'Member'}) - self.assertEqual(f.name, 'Member') - - # Missing stuff still fails after a second get - self.assertRaises(AttributeError, getattr, f, 'blahblah') - - def test_eq(self): - # Two resources with same ID: never equal if their info is not equal - r1 = base.Resource(None, {'id': 1, 'name': 'hi'}) - r2 = base.Resource(None, {'id': 1, 'name': 'hello'}) - self.assertNotEqual(r1, r2) - self.assertTrue(r1 != r2) - - # Two resources with same ID: equal if their info is equal - # The truth of r1==r2 does not imply that r1!=r2 is false in PY2. - # Test that inequality operator is defined and that comparing equal - # items returns False - r1 = base.Resource(None, {'id': 1, 'name': 'hello'}) - r2 = base.Resource(None, {'id': 1, 'name': 'hello'}) - self.assertTrue(r1 == r2) - self.assertFalse(r1 != r2) - - # Two resources of different types: never equal - r1 = base.Resource(None, {'id': 1}) - r2 = roles.Role(None, {'id': 1}) - self.assertNotEqual(r1, r2) - self.assertTrue(r1 != r2) - - # Two resources with no ID: equal if their info is equal - # The truth of r1==r2 does not imply that r1!=r2 is false in PY2. - # Test that inequality operator is defined and that comparing equal - # items returns False. - r1 = base.Resource(None, {'name': 'joe', 'age': 12}) - r2 = base.Resource(None, {'name': 'joe', 'age': 12}) - self.assertTrue(r1 == r2) - self.assertFalse(r1 != r2) - - r1 = base.Resource(None, {'id': 1}) - self.assertNotEqual(r1, object()) - self.assertTrue(r1 != object()) - self.assertNotEqual(r1, {'id': 1}) - self.assertTrue(r1 != {'id': 1}) - - def test_human_id(self): - r = base.Resource(None, {"name": "1 of !"}) - self.assertIsNone(r.human_id) - r = HumanReadable(None, {"name": "1 of !"}) - self.assertEqual(r.human_id, "1-of") - - def test_non_ascii_attr(self): - r_dict = {"name": "foobar", - u"тест": "1234", - u"тест2": u"привет мир"} - - r = base.Resource(None, r_dict) - self.assertEqual(r.name, "foobar") - self.assertEqual(r.to_dict(), r_dict) - - -class ManagerTest(utils.TestCase): - body = {"hello": {"hi": 1}} - url = "/test-url" - - def setUp(self): - super(ManagerTest, self).setUp() - - auth = v2.Token(auth_url='http://127.0.0.1:5000', - token=self.TEST_TOKEN) - session_ = session.Session(auth=auth) - self.client = client.Client(session=session_)._adapter - - self.mgr = base.Manager(self.client) - self.mgr.resource_class = base.Resource - - def test_api(self): - with self.deprecations.expect_deprecations_here(): - self.assertEqual(self.mgr.api, self.client) - - def test_get(self): - get_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'get', autospec=True, return_value=(None, self.body)) - ).mock - rsrc = self.mgr._get(self.url, "hello") - get_mock.assert_called_once_with(self.url) - self.assertEqual(rsrc.hi, 1) - - def test_post(self): - post_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'post', autospec=True, return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._post(self.url, self.body, "hello") - post_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hi, 1) - - post_mock.reset_mock() - - rsrc = self.mgr._post(self.url, self.body, "hello", return_raw=True) - post_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc["hi"], 1) - - def test_put(self): - put_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'put', autospec=True, return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._put(self.url, self.body, "hello") - put_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hi, 1) - - put_mock.reset_mock() - - rsrc = self.mgr._put(self.url, self.body) - put_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hello["hi"], 1) - - def test_patch(self): - patch_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'patch', autospec=True, - return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._patch(self.url, self.body, "hello") - patch_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hi, 1) - - patch_mock.reset_mock() - - rsrc = self.mgr._patch(self.url, self.body) - patch_mock.assert_called_once_with(self.url, body=self.body) - self.assertEqual(rsrc.hello["hi"], 1) - - def test_update(self): - patch_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'patch', autospec=True, - return_value=(None, self.body)) - ).mock - - put_mock = self.useFixture(fixtures.MockPatchObject( - self.client, 'put', autospec=True, return_value=(None, self.body)) - ).mock - - rsrc = self.mgr._update( - self.url, body=self.body, response_key="hello", method="PATCH", - management=False) - patch_mock.assert_called_once_with( - self.url, management=False, body=self.body) - self.assertEqual(rsrc.hi, 1) - - rsrc = self.mgr._update( - self.url, body=None, response_key="hello", method="PUT", - management=True) - put_mock.assert_called_once_with(self.url, management=True, body=None) - self.assertEqual(rsrc.hi, 1) diff --git a/keystoneclient/tests/unit/test_cms.py b/keystoneclient/tests/unit/test_cms.py deleted file mode 100644 index 11078aee..00000000 --- a/keystoneclient/tests/unit/test_cms.py +++ /dev/null @@ -1,201 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import errno -import os -import subprocess - -import mock -import testresources -from testtools import matchers - -from keystoneclient.common import cms -from keystoneclient import exceptions -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils - - -class CMSTest(utils.TestCase, testresources.ResourcedTestCase): - """Unit tests for the keystoneclient.common.cms module.""" - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def __init__(self, *args, **kwargs): - super(CMSTest, self).__init__(*args, **kwargs) - process = subprocess.Popen(['openssl', 'version'], - stdout=subprocess.PIPE) - out, err = process.communicate() - # Example output: 'OpenSSL 0.9.8za 5 Jun 2014' - openssl_version = out.split()[1] - - if err or openssl_version.startswith(b'0'): - raise Exception('Your version of OpenSSL is not supported. ' - 'You will need to update it to 1.0 or later.') - - def _raise_OSError(*args): - e = OSError() - e.errno = errno.EPIPE - raise e - - def test_cms_verify(self): - self.assertRaises(exceptions.CertificateConfigError, - cms.cms_verify, - 'data', - 'no_exist_cert_file', - 'no_exist_ca_file') - - def test_token_tocms_to_token(self): - with open(os.path.join(client_fixtures.CMSDIR, - 'auth_token_scoped.pem')) as f: - AUTH_TOKEN_SCOPED_CMS = f.read() - - self.assertEqual(cms.token_to_cms(self.examples.SIGNED_TOKEN_SCOPED), - AUTH_TOKEN_SCOPED_CMS) - - tok = cms.cms_to_token(cms.token_to_cms( - self.examples.SIGNED_TOKEN_SCOPED)) - self.assertEqual(tok, self.examples.SIGNED_TOKEN_SCOPED) - - def test_asn1_token(self): - self.assertTrue(cms.is_asn1_token(self.examples.SIGNED_TOKEN_SCOPED)) - self.assertFalse(cms.is_asn1_token('FOOBAR')) - - def test_cms_sign_token_no_files(self): - self.assertRaises(subprocess.CalledProcessError, - cms.cms_sign_token, - self.examples.TOKEN_SCOPED_DATA, - '/no/such/file', '/no/such/key') - - def test_cms_sign_token_no_files_pkiz(self): - self.assertRaises(subprocess.CalledProcessError, - cms.pkiz_sign, - self.examples.TOKEN_SCOPED_DATA, - '/no/such/file', '/no/such/key') - - def test_cms_sign_token_success(self): - self.assertTrue( - cms.pkiz_sign(self.examples.TOKEN_SCOPED_DATA, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_KEY_FILE)) - - def test_cms_verify_token_no_files(self): - self.assertRaises(exceptions.CertificateConfigError, - cms.cms_verify, - self.examples.SIGNED_TOKEN_SCOPED, - '/no/such/file', '/no/such/key') - - def test_cms_verify_token_no_oserror(self): - with mock.patch('subprocess.Popen.communicate', - new=self._raise_OSError): - try: - cms.cms_verify("x", '/no/such/file', '/no/such/key') - except exceptions.CertificateConfigError as e: - self.assertIn('/no/such/file', e.output) - self.assertIn('Hit OSError ', e.output) - else: - self.fail('Expected exceptions.CertificateConfigError') - - def test_cms_verify_token_scoped(self): - cms_content = cms.token_to_cms(self.examples.SIGNED_TOKEN_SCOPED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_verify_token_scoped_expired(self): - cms_content = cms.token_to_cms( - self.examples.SIGNED_TOKEN_SCOPED_EXPIRED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_verify_token_unscoped(self): - cms_content = cms.token_to_cms(self.examples.SIGNED_TOKEN_UNSCOPED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_verify_token_v3_scoped(self): - cms_content = cms.token_to_cms(self.examples.SIGNED_v3_TOKEN_SCOPED) - self.assertTrue(cms.cms_verify(cms_content, - self.examples.SIGNING_CERT_FILE, - self.examples.SIGNING_CA_FILE)) - - def test_cms_hash_token_no_token_id(self): - token_id = None - self.assertThat(cms.cms_hash_token(token_id), matchers.Is(None)) - - def test_cms_hash_token_not_pki(self): - """If the token_id is not a PKI token then it returns the token_id.""" - token = 'something' - self.assertFalse(cms.is_asn1_token(token)) - self.assertThat(cms.cms_hash_token(token), matchers.Is(token)) - - def test_cms_hash_token_default_md5(self): - """The default hash method is md5.""" - token = self.examples.SIGNED_TOKEN_SCOPED - token_id_default = cms.cms_hash_token(token) - token_id_md5 = cms.cms_hash_token(token, mode='md5') - self.assertThat(token_id_default, matchers.Equals(token_id_md5)) - # md5 hash is 32 chars. - self.assertThat(token_id_default, matchers.HasLength(32)) - - def test_cms_hash_token_sha256(self): - """Can also hash with sha256.""" - token = self.examples.SIGNED_TOKEN_SCOPED - token_id = cms.cms_hash_token(token, mode='sha256') - # sha256 hash is 64 chars. - self.assertThat(token_id, matchers.HasLength(64)) - - @mock.patch('keystoneclient.common.cms._check_files_accessible') - def test_process_communicate_handle_oserror_epipe(self, files_acc_mock): - process_mock = mock.Mock() - process_mock.communicate = self._raise_OSError - process_mock.stderr = mock.Mock() - process_mock.stderr.read = mock.Mock(return_value='proc stderr') - files_acc_mock.return_value = 1, ('file_path', 'fileerror') - output, err, retcode = cms._process_communicate_handle_oserror( - process_mock, '', []) - - self.assertEqual((output, retcode), ('', 1)) - self.assertIn('file_path', err) - self.assertIn('fileerror', err) - self.assertIn('proc stderr', err) - - @mock.patch('keystoneclient.common.cms._check_files_accessible') - def test_process_communicate_handle_oserror_epipe_files_ok( - self, files_acc_mock): - process_mock = mock.Mock() - process_mock.communicate = self._raise_OSError - process_mock.stderr = mock.Mock() - process_mock.stderr.read = mock.Mock(return_value='proc stderr') - files_acc_mock.return_value = -1, None - output, err, retcode = cms._process_communicate_handle_oserror( - process_mock, '', []) - - self.assertEqual((output, retcode), ('', -1)) - self.assertIn('proc stderr', err) - - def test_process_communicate_handle_oserror_no_exception(self): - process_mock = mock.Mock() - process_mock.communicate.return_value = 'out', 'err' - process_mock.poll.return_value = 0 - - output, err, retcode = cms._process_communicate_handle_oserror( - process_mock, '', []) - - self.assertEqual(output, 'out') - self.assertEqual(err, 'err') - self.assertEqual(retcode, 0) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/test_discovery.py b/keystoneclient/tests/unit/test_discovery.py deleted file mode 100644 index f9d5dbfa..00000000 --- a/keystoneclient/tests/unit/test_discovery.py +++ /dev/null @@ -1,838 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import re -import uuid - -from keystoneauth1 import fixture -from oslo_serialization import jsonutils -import six -from testtools import matchers - -from keystoneclient import _discover -from keystoneclient.auth import token_endpoint -from keystoneclient import client -from keystoneclient import discover -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit import utils -from keystoneclient.v2_0 import client as v2_client -from keystoneclient.v3 import client as v3_client - - -BASE_HOST = 'http://keystone.example.com' -BASE_URL = "%s:5000/" % BASE_HOST -UPDATED = '2013-03-06T00:00:00Z' - -TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "adminURL": "%s:8774/v1.0" % BASE_HOST, - "region": "RegionOne", - "internalURL": "%s://127.0.0.1:8774/v1.0" % BASE_HOST, - "publicURL": "%s:8774/v1.0/" % BASE_HOST - }], - "type": "nova_compat", - "name": "nova_compat" -}, { - "endpoints": [{ - "adminURL": "http://nova/novapi/admin", - "region": "RegionOne", - "internalURL": "http://nova/novapi/internal", - "publicURL": "http://nova/novapi/public" - }], - "type": "compute", - "name": "nova" -}, { - "endpoints": [{ - "adminURL": "http://glance/glanceapi/admin", - "region": "RegionOne", - "internalURL": "http://glance/glanceapi/internal", - "publicURL": "http://glance/glanceapi/public" - }], - "type": "image", - "name": "glance" -}, { - "endpoints": [{ - "adminURL": "%s:35357/v2.0" % BASE_HOST, - "region": "RegionOne", - "internalURL": "%s:5000/v2.0" % BASE_HOST, - "publicURL": "%s:5000/v2.0" % BASE_HOST - }], - "type": "identity", - "name": "keystone" -}, { - "endpoints": [{ - "adminURL": "http://swift/swiftapi/admin", - "region": "RegionOne", - "internalURL": "http://swift/swiftapi/internal", - "publicURL": "http://swift/swiftapi/public" - }], - "type": "object-store", - "name": "swift" -}] - -V2_URL = "%sv2.0" % BASE_URL -V2_VERSION = fixture.V2Discovery(V2_URL) -V2_VERSION.updated_str = UPDATED - -V2_AUTH_RESPONSE = jsonutils.dumps({ - "access": { - "token": { - "expires": "2020-01-01T00:00:10.000123Z", - "id": 'fakeToken', - "tenant": { - "id": '1' - }, - }, - "user": { - "id": 'test' - }, - "serviceCatalog": TEST_SERVICE_CATALOG, - }, -}) - -V3_URL = "%sv3" % BASE_URL -V3_VERSION = fixture.V3Discovery(V3_URL) -V3_MEDIA_TYPES = V3_VERSION.media_types -V3_VERSION.updated_str = UPDATED - -V3_TOKEN = six.u('3e2813b7ba0b4006840c3825860b86ed'), -V3_AUTH_RESPONSE = jsonutils.dumps({ - "token": { - "methods": [ - "token", - "password" - ], - - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": '1', - "name": 'test-domain' - }, - "id": '1', - "name": 'test-project' - }, - "user": { - "domain": { - "id": '1', - "name": 'test-domain' - }, - "id": '1', - "name": 'test-user' - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - }, -}) - -CINDER_EXAMPLES = { - "versions": [ - { - "status": "CURRENT", - "updated": "2012-01-04T11:33:21Z", - "id": "v1.0", - "links": [ - { - "href": "%sv1/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "CURRENT", - "updated": "2012-11-21T11:33:21Z", - "id": "v2.0", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - } - ] -} - -GLANCE_EXAMPLES = { - "versions": [ - { - "status": "CURRENT", - "id": "v2.2", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "SUPPORTED", - "id": "v2.1", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "SUPPORTED", - "id": "v2.0", - "links": [ - { - "href": "%sv2/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "CURRENT", - "id": "v1.1", - "links": [ - { - "href": "%sv1/" % BASE_URL, - "rel": "self" - } - ] - }, - { - "status": "SUPPORTED", - "id": "v1.0", - "links": [ - { - "href": "%sv1/" % BASE_URL, - "rel": "self" - } - ] - } - ] -} - - -def _create_version_list(versions): - return jsonutils.dumps({'versions': {'values': versions}}) - - -def _create_single_version(version): - return jsonutils.dumps({'version': version}) - - -V3_VERSION_LIST = _create_version_list([V3_VERSION, V2_VERSION]) -V2_VERSION_LIST = _create_version_list([V2_VERSION]) - -V3_VERSION_ENTRY = _create_single_version(V3_VERSION) -V2_VERSION_ENTRY = _create_single_version(V2_VERSION) - - -class AvailableVersionsTests(utils.TestCase): - - def setUp(self): - super(AvailableVersionsTests, self).setUp() - self.deprecations.expect_deprecations() - - def test_available_versions_basics(self): - examples = {'keystone': V3_VERSION_LIST, - 'cinder': jsonutils.dumps(CINDER_EXAMPLES), - 'glance': jsonutils.dumps(GLANCE_EXAMPLES)} - - for path, text in examples.items(): - url = "%s%s" % (BASE_URL, path) - - self.requests_mock.get(url, status_code=300, text=text) - versions = discover.available_versions(url) - - for v in versions: - for n in ('id', 'status', 'links'): - msg = '%s missing from %s version data' % (n, path) - self.assertThat(v, matchers.Annotate(msg, - matchers.Contains(n))) - - def test_available_versions_individual(self): - self.requests_mock.get(V3_URL, status_code=200, text=V3_VERSION_ENTRY) - - versions = discover.available_versions(V3_URL) - - for v in versions: - self.assertEqual(v['id'], 'v3.0') - self.assertEqual(v['status'], 'stable') - self.assertIn('media-types', v) - self.assertIn('links', v) - - def test_available_keystone_data(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - versions = discover.available_versions(BASE_URL) - self.assertEqual(2, len(versions)) - - for v in versions: - self.assertIn(v['id'], ('v2.0', 'v3.0')) - self.assertEqual(v['updated'], UPDATED) - self.assertEqual(v['status'], 'stable') - - if v['id'] == 'v3.0': - self.assertEqual(v['media-types'], V3_MEDIA_TYPES) - - def test_available_cinder_data(self): - text = jsonutils.dumps(CINDER_EXAMPLES) - self.requests_mock.get(BASE_URL, status_code=300, text=text) - - versions = discover.available_versions(BASE_URL) - self.assertEqual(2, len(versions)) - - for v in versions: - self.assertEqual(v['status'], 'CURRENT') - if v['id'] == 'v1.0': - self.assertEqual(v['updated'], '2012-01-04T11:33:21Z') - elif v['id'] == 'v2.0': - self.assertEqual(v['updated'], '2012-11-21T11:33:21Z') - else: - self.fail("Invalid version found") - - def test_available_glance_data(self): - text = jsonutils.dumps(GLANCE_EXAMPLES) - self.requests_mock.get(BASE_URL, status_code=200, text=text) - - versions = discover.available_versions(BASE_URL) - self.assertEqual(5, len(versions)) - - for v in versions: - if v['id'] in ('v2.2', 'v1.1'): - self.assertEqual(v['status'], 'CURRENT') - elif v['id'] in ('v2.1', 'v2.0', 'v1.0'): - self.assertEqual(v['status'], 'SUPPORTED') - else: - self.fail("Invalid version found") - - -class ClientDiscoveryTests(utils.TestCase): - - def setUp(self): - super(ClientDiscoveryTests, self).setUp() - self.deprecations.expect_deprecations() - - def assertCreatesV3(self, **kwargs): - self.requests_mock.post('%s/auth/tokens' % V3_URL, - text=V3_AUTH_RESPONSE, - headers={'X-Subject-Token': V3_TOKEN}) - - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - keystone = client.Client(**kwargs) - self.assertIsInstance(keystone, v3_client.Client) - return keystone - - def assertCreatesV2(self, **kwargs): - self.requests_mock.post("%s/tokens" % V2_URL, text=V2_AUTH_RESPONSE) - - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - keystone = client.Client(**kwargs) - self.assertIsInstance(keystone, v2_client.Client) - return keystone - - def assertVersionNotAvailable(self, **kwargs): - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - - self.assertRaises(exceptions.VersionNotAvailable, - client.Client, **kwargs) - - def assertDiscoveryFailure(self, **kwargs): - kwargs.setdefault('username', 'foo') - kwargs.setdefault('password', 'bar') - - self.assertRaises(exceptions.DiscoveryFailure, - client.Client, **kwargs) - - def test_discover_v3(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.assertCreatesV3(auth_url=BASE_URL) - - def test_discover_v2(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V2_VERSION_LIST) - self.requests_mock.post("%s/tokens" % V2_URL, text=V2_AUTH_RESPONSE) - - self.assertCreatesV2(auth_url=BASE_URL) - - def test_discover_endpoint_v2(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V2_VERSION_LIST) - self.assertCreatesV2(endpoint=BASE_URL, token='fake-token') - - def test_discover_endpoint_v3(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - self.assertCreatesV3(endpoint=BASE_URL, token='fake-token') - - def test_discover_invalid_major_version(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.assertVersionNotAvailable(auth_url=BASE_URL, version=5) - - def test_discover_200_response_fails(self): - self.requests_mock.get(BASE_URL, text='ok') - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_discover_minor_greater_than_available_fails(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.assertVersionNotAvailable(endpoint=BASE_URL, version=3.4) - - def test_discover_individual_version_v2(self): - self.requests_mock.get(V2_URL, text=V2_VERSION_ENTRY) - - self.assertCreatesV2(auth_url=V2_URL) - - def test_discover_individual_version_v3(self): - self.requests_mock.get(V3_URL, text=V3_VERSION_ENTRY) - - self.assertCreatesV3(auth_url=V3_URL) - - def test_discover_individual_endpoint_v2(self): - self.requests_mock.get(V2_URL, text=V2_VERSION_ENTRY) - self.assertCreatesV2(endpoint=V2_URL, token='fake-token') - - def test_discover_individual_endpoint_v3(self): - self.requests_mock.get(V3_URL, text=V3_VERSION_ENTRY) - self.assertCreatesV3(endpoint=V3_URL, token='fake-token') - - def test_discover_fail_to_create_bad_individual_version(self): - self.requests_mock.get(V2_URL, text=V2_VERSION_ENTRY) - self.requests_mock.get(V3_URL, text=V3_VERSION_ENTRY) - - self.assertVersionNotAvailable(auth_url=V2_URL, version=3) - self.assertVersionNotAvailable(auth_url=V3_URL, version=2) - - def test_discover_unstable_versions(self): - version_list = fixture.DiscoveryList(BASE_URL, v3_status='beta') - self.requests_mock.get(BASE_URL, status_code=300, json=version_list) - - self.assertCreatesV2(auth_url=BASE_URL) - self.assertVersionNotAvailable(auth_url=BASE_URL, version=3) - self.assertCreatesV3(auth_url=BASE_URL, unstable=True) - - def test_discover_forwards_original_ip(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - ip = '192.168.1.1' - self.assertCreatesV3(auth_url=BASE_URL, original_ip=ip) - - self.assertThat(self.requests_mock.last_request.headers['forwarded'], - matchers.Contains(ip)) - - def test_discover_bad_args(self): - self.assertRaises(exceptions.DiscoveryFailure, - client.Client) - - def test_discover_bad_response(self): - self.requests_mock.get(BASE_URL, status_code=300, json={'FOO': 'BAR'}) - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_discovery_ignore_invalid(self): - resp = [{'id': 'v3.0', - 'links': [1, 2, 3, 4], # invalid links - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED}] - self.requests_mock.get(BASE_URL, status_code=300, - text=_create_version_list(resp)) - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_ignore_entry_without_links(self): - v3 = V3_VERSION.copy() - v3['links'] = [] - self.requests_mock.get(BASE_URL, status_code=300, - text=_create_version_list([v3, V2_VERSION])) - self.assertCreatesV2(auth_url=BASE_URL) - - def test_ignore_entry_without_status(self): - v3 = V3_VERSION.copy() - del v3['status'] - self.requests_mock.get(BASE_URL, status_code=300, - text=_create_version_list([v3, V2_VERSION])) - self.assertCreatesV2(auth_url=BASE_URL) - - def test_greater_version_than_required(self): - versions = fixture.DiscoveryList(BASE_URL, v3_id='v3.6') - self.requests_mock.get(BASE_URL, json=versions) - self.assertCreatesV3(auth_url=BASE_URL, version=(3, 4)) - - def test_lesser_version_than_required(self): - versions = fixture.DiscoveryList(BASE_URL, v3_id='v3.4') - self.requests_mock.get(BASE_URL, json=versions) - self.assertVersionNotAvailable(auth_url=BASE_URL, version=(3, 6)) - - def test_bad_response(self): - self.requests_mock.get(BASE_URL, status_code=300, text="Ugly Duckling") - self.assertDiscoveryFailure(auth_url=BASE_URL) - - def test_pass_client_arguments(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V2_VERSION_LIST) - kwargs = {'original_ip': '100', 'use_keyring': False, - 'stale_duration': 15} - - cl = self.assertCreatesV2(auth_url=BASE_URL, **kwargs) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(cl.original_ip, '100') - self.assertEqual(cl.stale_duration, 15) - self.assertFalse(cl.use_keyring) - - def test_overriding_stored_kwargs(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - self.requests_mock.post("%s/auth/tokens" % V3_URL, - text=V3_AUTH_RESPONSE, - headers={'X-Subject-Token': V3_TOKEN}) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL, debug=False, - username='foo') - client = disc.create_client(debug=True, password='bar') - - self.assertIsInstance(client, v3_client.Client) - self.assertFalse(disc._client_kwargs['debug']) - self.assertEqual(client.username, 'foo') - self.assertEqual(client.password, 'bar') - - def test_available_versions(self): - self.requests_mock.get(BASE_URL, - status_code=300, - text=V3_VERSION_ENTRY) - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - with self.deprecations.expect_deprecations_here(): - versions = disc.available_versions() - self.assertEqual(1, len(versions)) - self.assertEqual(V3_VERSION, versions[0]) - - def test_unknown_client_version(self): - V4_VERSION = {'id': 'v4.0', - 'links': [{'href': 'http://url', 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED} - versions = fixture.DiscoveryList() - versions.add_version(V4_VERSION) - self.requests_mock.get(BASE_URL, status_code=300, json=versions) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - self.assertRaises(exceptions.DiscoveryFailure, - disc.create_client, version=4) - - def test_discovery_fail_for_missing_v3(self): - versions = fixture.DiscoveryList(v2=True, v3=False) - self.requests_mock.get(BASE_URL, status_code=300, json=versions) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - self.assertRaises(exceptions.DiscoveryFailure, - disc.create_client, version=(3, 0)) - - def _do_discovery_call(self, token=None, **kwargs): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - if not token: - token = uuid.uuid4().hex - - url = 'http://testurl' - - with self.deprecations.expect_deprecations_here(): - a = token_endpoint.Token(url, token) - s = session.Session(auth=a) - - # will default to true as there is a plugin on the session - discover.Discover(s, auth_url=BASE_URL, **kwargs) - - self.assertEqual(BASE_URL, self.requests_mock.last_request.url) - - def test_setting_authenticated_true(self): - token = uuid.uuid4().hex - self._do_discovery_call(token) - self.assertRequestHeaderEqual('X-Auth-Token', token) - - def test_setting_authenticated_false(self): - self._do_discovery_call(authenticated=False) - self.assertNotIn('X-Auth-Token', - self.requests_mock.last_request.headers) - - -class DiscoverQueryTests(utils.TestCase): - - def test_available_keystone_data(self): - self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - versions = disc.version_data() - - self.assertEqual((2, 0), versions[0]['version']) - self.assertEqual('stable', versions[0]['raw_status']) - self.assertEqual(V2_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[1]['version']) - self.assertEqual('stable', versions[1]['raw_status']) - self.assertEqual(V3_URL, versions[1]['url']) - - version = disc.data_for('v3.0') - self.assertEqual((3, 0), version['version']) - self.assertEqual('stable', version['raw_status']) - self.assertEqual(V3_URL, version['url']) - - version = disc.data_for(2) - self.assertEqual((2, 0), version['version']) - self.assertEqual('stable', version['raw_status']) - self.assertEqual(V2_URL, version['url']) - - self.assertIsNone(disc.url_for('v4')) - self.assertEqual(V3_URL, disc.url_for('v3')) - self.assertEqual(V2_URL, disc.url_for('v2')) - - def test_available_cinder_data(self): - text = jsonutils.dumps(CINDER_EXAMPLES) - self.requests_mock.get(BASE_URL, status_code=300, text=text) - - v1_url = "%sv1/" % BASE_URL - v2_url = "%sv2/" % BASE_URL - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - versions = disc.version_data() - - self.assertEqual((1, 0), versions[0]['version']) - self.assertEqual('CURRENT', versions[0]['raw_status']) - self.assertEqual(v1_url, versions[0]['url']) - self.assertEqual((2, 0), versions[1]['version']) - self.assertEqual('CURRENT', versions[1]['raw_status']) - self.assertEqual(v2_url, versions[1]['url']) - - version = disc.data_for('v2.0') - self.assertEqual((2, 0), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v2_url, version['url']) - - version = disc.data_for(1) - self.assertEqual((1, 0), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v1_url, version['url']) - - self.assertIsNone(disc.url_for('v3')) - self.assertEqual(v2_url, disc.url_for('v2')) - self.assertEqual(v1_url, disc.url_for('v1')) - - def test_available_glance_data(self): - text = jsonutils.dumps(GLANCE_EXAMPLES) - self.requests_mock.get(BASE_URL, text=text) - - v1_url = "%sv1/" % BASE_URL - v2_url = "%sv2/" % BASE_URL - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - versions = disc.version_data() - - self.assertEqual((1, 0), versions[0]['version']) - self.assertEqual('SUPPORTED', versions[0]['raw_status']) - self.assertEqual(v1_url, versions[0]['url']) - self.assertEqual((1, 1), versions[1]['version']) - self.assertEqual('CURRENT', versions[1]['raw_status']) - self.assertEqual(v1_url, versions[1]['url']) - self.assertEqual((2, 0), versions[2]['version']) - self.assertEqual('SUPPORTED', versions[2]['raw_status']) - self.assertEqual(v2_url, versions[2]['url']) - self.assertEqual((2, 1), versions[3]['version']) - self.assertEqual('SUPPORTED', versions[3]['raw_status']) - self.assertEqual(v2_url, versions[3]['url']) - self.assertEqual((2, 2), versions[4]['version']) - self.assertEqual('CURRENT', versions[4]['raw_status']) - self.assertEqual(v2_url, versions[4]['url']) - - for ver in (2, 2.1, 2.2): - version = disc.data_for(ver) - self.assertEqual((2, 2), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v2_url, version['url']) - self.assertEqual(v2_url, disc.url_for(ver)) - - for ver in (1, 1.1): - version = disc.data_for(ver) - self.assertEqual((1, 1), version['version']) - self.assertEqual('CURRENT', version['raw_status']) - self.assertEqual(v1_url, version['url']) - self.assertEqual(v1_url, disc.url_for(ver)) - - self.assertIsNone(disc.url_for('v3')) - self.assertIsNone(disc.url_for('v2.3')) - - def test_allow_deprecated(self): - status = 'deprecated' - version_list = [{'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': status, - 'updated': UPDATED}] - text = jsonutils.dumps({'versions': version_list}) - self.requests_mock.get(BASE_URL, text=text) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - # deprecated is allowed by default - versions = disc.version_data(allow_deprecated=False) - self.assertEqual(0, len(versions)) - - versions = disc.version_data(allow_deprecated=True) - self.assertEqual(1, len(versions)) - self.assertEqual(status, versions[0]['raw_status']) - self.assertEqual(V3_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[0]['version']) - - def test_allow_experimental(self): - status = 'experimental' - version_list = [{'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': status, - 'updated': UPDATED}] - text = jsonutils.dumps({'versions': version_list}) - self.requests_mock.get(BASE_URL, text=text) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - versions = disc.version_data() - self.assertEqual(0, len(versions)) - - versions = disc.version_data(allow_experimental=True) - self.assertEqual(1, len(versions)) - self.assertEqual(status, versions[0]['raw_status']) - self.assertEqual(V3_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[0]['version']) - - def test_allow_unknown(self): - status = 'abcdef' - version_list = fixture.DiscoveryList(BASE_URL, v2=False, - v3_status=status) - self.requests_mock.get(BASE_URL, json=version_list) - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - versions = disc.version_data() - self.assertEqual(0, len(versions)) - - versions = disc.version_data(allow_unknown=True) - self.assertEqual(1, len(versions)) - self.assertEqual(status, versions[0]['raw_status']) - self.assertEqual(V3_URL, versions[0]['url']) - self.assertEqual((3, 0), versions[0]['version']) - - def test_ignoring_invalid_lnks(self): - version_list = [{'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED}, - {'id': 'v3.1', - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED}, - {'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED, - 'links': [{'href': V3_URL, 'rel': 'self'}], - }] - - text = jsonutils.dumps({'versions': version_list}) - self.requests_mock.get(BASE_URL, text=text) - - # Creating Discover not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - disc = discover.Discover(auth_url=BASE_URL) - - # raw_version_data will return all choices, even invalid ones - versions = disc.raw_version_data() - self.assertEqual(3, len(versions)) - - # only the version with both id and links will be actually returned - versions = disc.version_data() - self.assertEqual(1, len(versions)) - - -class CatalogHackTests(utils.TestCase): - - TEST_URL = 'http://keystone.server:5000/v2.0' - OTHER_URL = 'http://other.server:5000/path' - - IDENTITY = 'identity' - - BASE_URL = 'http://keystone.server:5000/' - V2_URL = BASE_URL + 'v2.0' - V3_URL = BASE_URL + 'v3' - - def setUp(self): - super(CatalogHackTests, self).setUp() - self.hacks = _discover._VersionHacks() - self.hacks.add_discover_hack(self.IDENTITY, - re.compile('/v2.0/?$'), - '/') - - def test_version_hacks(self): - self.assertEqual(self.BASE_URL, - self.hacks.get_discover_hack(self.IDENTITY, - self.V2_URL)) - - self.assertEqual(self.BASE_URL, - self.hacks.get_discover_hack(self.IDENTITY, - self.V2_URL + '/')) - - self.assertEqual(self.OTHER_URL, - self.hacks.get_discover_hack(self.IDENTITY, - self.OTHER_URL)) - - def test_ignored_non_service_type(self): - self.assertEqual(self.V2_URL, - self.hacks.get_discover_hack('other', self.V2_URL)) - - -class DiscoverUtils(utils.TestCase): - - def test_version_number(self): - def assertVersion(inp, out): - self.assertEqual(out, _discover.normalize_version_number(inp)) - - def versionRaises(inp): - self.assertRaises(TypeError, - _discover.normalize_version_number, - inp) - - assertVersion('v1.2', (1, 2)) - assertVersion('v11', (11, 0)) - assertVersion('1.2', (1, 2)) - assertVersion('1.5.1', (1, 5, 1)) - assertVersion('1', (1, 0)) - assertVersion(1, (1, 0)) - assertVersion(5.2, (5, 2)) - assertVersion((6, 1), (6, 1)) - assertVersion([1, 4], (1, 4)) - - versionRaises('hello') - versionRaises('1.a') - versionRaises('vacuum') diff --git a/keystoneclient/tests/unit/test_ec2utils.py b/keystoneclient/tests/unit/test_ec2utils.py deleted file mode 100644 index 1d8809b2..00000000 --- a/keystoneclient/tests/unit/test_ec2utils.py +++ /dev/null @@ -1,306 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from __future__ import unicode_literals - -import testtools - -from keystoneclient.contrib.ec2 import utils -from keystoneclient.tests.unit import client_fixtures - - -class Ec2SignerTest(testtools.TestCase): - - def setUp(self): - super(Ec2SignerTest, self).setUp() - self.useFixture(client_fixtures.Deprecations()) - self.access = '966afbde20b84200ae4e62e09acf46b2' - self.secret = '89cdf9e94e2643cab35b8b8ac5a51f83' - self.signer = utils.Ec2Signer(self.secret) - - def test_v4_creds_header(self): - auth_str = 'AWS4-HMAC-SHA256 blah' - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {}, - 'headers': {'Authorization': auth_str}} - self.assertTrue(self.signer._v4_creds(credentials)) - - def test_v4_creds_param(self): - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'X-Amz-Algorithm': 'AWS4-HMAC-SHA256'}, - 'headers': {}} - self.assertTrue(self.signer._v4_creds(credentials)) - - def test_v4_creds_false(self): - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '0', - 'AWSAccessKeyId': self.access, - 'Timestamp': '2012-11-27T11:47:02Z', - 'Action': 'Foo'}} - self.assertFalse(self.signer._v4_creds(credentials)) - - def test_generate_0(self): - """Test generate function for v0 signature.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '0', - 'AWSAccessKeyId': self.access, - 'Timestamp': '2012-11-27T11:47:02Z', - 'Action': 'Foo'}} - signature = self.signer.generate(credentials) - expected = 'SmXQEZAUdQw5glv5mX8mmixBtas=' - self.assertEqual(signature, expected) - - def test_generate_1(self): - """Test generate function for v1 signature.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '1', - 'AWSAccessKeyId': self.access}} - signature = self.signer.generate(credentials) - expected = 'VRnoQH/EhVTTLhwRLfuL7jmFW9c=' - self.assertEqual(signature, expected) - - def test_generate_v2_SHA256(self): - """Test generate function for v2 signature, SHA256.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '2', - 'AWSAccessKeyId': self.access}} - signature = self.signer.generate(credentials) - expected = 'odsGmT811GffUO0Eu13Pq+xTzKNIjJ6NhgZU74tYX/w=' - self.assertEqual(signature, expected) - - def test_generate_v2_SHA1(self): - """Test generate function for v2 signature, SHA1.""" - credentials = {'host': '127.0.0.1', - 'verb': 'GET', - 'path': '/v1/', - 'params': {'SignatureVersion': '2', - 'AWSAccessKeyId': self.access}} - self.signer.hmac_256 = None - signature = self.signer.generate(credentials) - expected = 'ZqCxMI4ZtTXWI175743mJ0hy/Gc=' - self.assertEqual(signature, expected) - - def test_generate_v4(self): - """Test v4 generator with data from AWS docs example. - - see: - http://docs.aws.amazon.com/general/latest/gr/ - sigv4-create-canonical-request.html - and - http://docs.aws.amazon.com/general/latest/gr/ - sigv4-signed-request-examples.html - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'iam.amazonaws.com', - 'Authorization': auth_str} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {'Action': 'CreateUser', - 'UserName': 'NewUser', - 'Version': '2010-05-08', - 'X-Amz-Algorithm': 'AWS4-HMAC-SHA256', - 'X-Amz-Credential': 'AKIAEXAMPLE/20140611/' - 'us-east-1/iam/aws4_request', - 'X-Amz-Date': '20140611T231318Z', - 'X-Amz-Expires': '30', - 'X-Amz-SignedHeaders': 'host', - 'X-Amz-Signature': 'ced6826de92d2bdeed8f846f0bf508e8' - '559e98e4b0199114b84c54174deb456c'} - credentials = {'host': 'iam.amazonaws.com', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - expected = ('ced6826de92d2bdeed8f846f0bf508e8' - '559e98e4b0199114b84c54174deb456c') - self.assertEqual(signature, expected) - - def test_generate_v4_port(self): - """Test v4 generator with host:port format.""" - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('26dd92ea79aaa49f533d13b1055acdc' - 'd7d7321460d64621f96cc79c4f4d4ab2b') - self.assertEqual(signature, expected) - - def test_generate_v4_port_strip(self): - """Test v4 generator with host:port format for old boto version. - - Validate for old (<2.9.3) version of boto, where the port should - be stripped to match boto behavior. - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str, - 'User-Agent': 'Boto/2.9.2 (linux2)'} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('9a4b2276a5039ada3b90f72ea8ec1745' - '14b92b909fb106b22ad910c5d75a54f4') - self.assertEqual(expected, signature) - - def test_generate_v4_port_nostrip(self): - """Test v4 generator with host:port format for new boto version. - - Validate for new (>=2.9.3) version of boto, where the port should - not be stripped. - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str, - 'User-Agent': 'Boto/2.9.3 (linux2)'} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('26dd92ea79aaa49f533d13b1055acdc' - 'd7d7321460d64621f96cc79c4f4d4ab2b') - self.assertEqual(expected, signature) - - def test_generate_v4_port_malformed_version(self): - """Test v4 generator with host:port format for malformed boto version. - - Validate for malformed version of boto, where the port should - not be stripped. - """ - # Create a new signer object with the AWS example key - secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' - signer = utils.Ec2Signer(secret) - - body_hash = ('b6359072c78d70ebee1e81adcbab4f0' - '1bf2c23245fa365ef83fe8f1f955085e2') - auth_str = ('AWS4-HMAC-SHA256 ' - 'Credential=AKIAIOSFODNN7EXAMPLE/20110909/' - 'us-east-1/iam/aws4_request,' - 'SignedHeaders=content-type;host;x-amz-date,') - headers = {'Content-type': - 'application/x-www-form-urlencoded; charset=utf-8', - 'X-Amz-Date': '20110909T233600Z', - 'Host': 'foo:8000', - 'Authorization': auth_str, - 'User-Agent': 'Boto/2.922 (linux2)'} - # Note the example in the AWS docs is inconsistent, previous - # examples specify no query string, but the final POST example - # does, apparently incorrectly since an empty parameter list - # aligns all steps and the final signature with the examples - params = {} - credentials = {'host': 'foo:8000', - 'verb': 'POST', - 'path': '/', - 'params': params, - 'headers': headers, - 'body_hash': body_hash} - signature = signer.generate(credentials) - - expected = ('26dd92ea79aaa49f533d13b1055acdc' - 'd7d7321460d64621f96cc79c4f4d4ab2b') - self.assertEqual(expected, signature) diff --git a/keystoneclient/tests/unit/test_fixtures.py b/keystoneclient/tests/unit/test_fixtures.py deleted file mode 100644 index d7fd26e6..00000000 --- a/keystoneclient/tests/unit/test_fixtures.py +++ /dev/null @@ -1,251 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - - -from keystoneclient import fixture -from keystoneclient.tests.unit import utils - - -class V2TokenTests(utils.TestCase): - - def test_unscoped(self): - token_id = uuid.uuid4().hex - user_id = uuid.uuid4().hex - user_name = uuid.uuid4().hex - - token = fixture.V2Token(token_id=token_id, - user_id=user_id, - user_name=user_name) - - self.assertEqual(token_id, token.token_id) - self.assertEqual(token_id, token['access']['token']['id']) - self.assertEqual(user_id, token.user_id) - self.assertEqual(user_id, token['access']['user']['id']) - self.assertEqual(user_name, token.user_name) - self.assertEqual(user_name, token['access']['user']['name']) - self.assertIsNone(token.trust_id) - - def test_tenant_scoped(self): - tenant_id = uuid.uuid4().hex - tenant_name = uuid.uuid4().hex - - token = fixture.V2Token(tenant_id=tenant_id, - tenant_name=tenant_name) - - self.assertEqual(tenant_id, token.tenant_id) - self.assertEqual(tenant_id, token['access']['token']['tenant']['id']) - self.assertEqual(tenant_name, token.tenant_name) - tn = token['access']['token']['tenant']['name'] - self.assertEqual(tenant_name, tn) - self.assertIsNone(token.trust_id) - - def test_trust_scoped(self): - trust_id = uuid.uuid4().hex - trustee_user_id = uuid.uuid4().hex - - token = fixture.V2Token(trust_id=trust_id, - trustee_user_id=trustee_user_id) - trust = token['access']['trust'] - - self.assertEqual(trust_id, token.trust_id) - self.assertEqual(trust_id, trust['id']) - self.assertEqual(trustee_user_id, token.trustee_user_id) - self.assertEqual(trustee_user_id, trust['trustee_user_id']) - - def test_roles(self): - role_id1 = uuid.uuid4().hex - role_name1 = uuid.uuid4().hex - role_id2 = uuid.uuid4().hex - role_name2 = uuid.uuid4().hex - - token = fixture.V2Token() - token.add_role(id=role_id1, name=role_name1) - token.add_role(id=role_id2, name=role_name2) - - role_names = token['access']['user']['roles'] - role_ids = token['access']['metadata']['roles'] - - self.assertEqual(set([role_id1, role_id2]), set(role_ids)) - for r in (role_name1, role_name2): - self.assertIn({'name': r}, role_names) - - def test_services(self): - service_type = uuid.uuid4().hex - service_name = uuid.uuid4().hex - endpoint_id = uuid.uuid4().hex - region = uuid.uuid4().hex - - public = uuid.uuid4().hex - admin = uuid.uuid4().hex - internal = uuid.uuid4().hex - - token = fixture.V2Token() - svc = token.add_service(type=service_type, name=service_name) - - svc.add_endpoint(public=public, - admin=admin, - internal=internal, - region=region, - id=endpoint_id) - - self.assertEqual(1, len(token['access']['serviceCatalog'])) - service = token['access']['serviceCatalog'][0]['endpoints'][0] - - self.assertEqual(public, service['publicURL']) - self.assertEqual(internal, service['internalURL']) - self.assertEqual(admin, service['adminURL']) - self.assertEqual(region, service['region']) - self.assertEqual(endpoint_id, service['id']) - - -class V3TokenTests(utils.TestCase): - - def test_unscoped(self): - user_id = uuid.uuid4().hex - user_name = uuid.uuid4().hex - user_domain_id = uuid.uuid4().hex - user_domain_name = uuid.uuid4().hex - - token = fixture.V3Token(user_id=user_id, - user_name=user_name, - user_domain_id=user_domain_id, - user_domain_name=user_domain_name) - - self.assertEqual(user_id, token.user_id) - self.assertEqual(user_id, token['token']['user']['id']) - self.assertEqual(user_name, token.user_name) - self.assertEqual(user_name, token['token']['user']['name']) - - user_domain = token['token']['user']['domain'] - - self.assertEqual(user_domain_id, token.user_domain_id) - self.assertEqual(user_domain_id, user_domain['id']) - self.assertEqual(user_domain_name, token.user_domain_name) - self.assertEqual(user_domain_name, user_domain['name']) - - def test_project_scoped(self): - project_id = uuid.uuid4().hex - project_name = uuid.uuid4().hex - project_domain_id = uuid.uuid4().hex - project_domain_name = uuid.uuid4().hex - - token = fixture.V3Token(project_id=project_id, - project_name=project_name, - project_domain_id=project_domain_id, - project_domain_name=project_domain_name) - - self.assertEqual(project_id, token.project_id) - self.assertEqual(project_id, token['token']['project']['id']) - self.assertEqual(project_name, token.project_name) - self.assertEqual(project_name, token['token']['project']['name']) - - project_domain = token['token']['project']['domain'] - - self.assertEqual(project_domain_id, token.project_domain_id) - self.assertEqual(project_domain_id, project_domain['id']) - self.assertEqual(project_domain_name, token.project_domain_name) - self.assertEqual(project_domain_name, project_domain['name']) - - def test_domain_scoped(self): - domain_id = uuid.uuid4().hex - domain_name = uuid.uuid4().hex - - token = fixture.V3Token(domain_id=domain_id, - domain_name=domain_name) - - self.assertEqual(domain_id, token.domain_id) - self.assertEqual(domain_id, token['token']['domain']['id']) - self.assertEqual(domain_name, token.domain_name) - self.assertEqual(domain_name, token['token']['domain']['name']) - - def test_roles(self): - role1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} - role2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} - - token = fixture.V3Token() - token.add_role(**role1) - token.add_role(**role2) - - self.assertEqual(2, len(token['token']['roles'])) - - self.assertIn(role1, token['token']['roles']) - self.assertIn(role2, token['token']['roles']) - - def test_trust_scoped(self): - trust_id = uuid.uuid4().hex - trustee_user_id = uuid.uuid4().hex - trustor_user_id = uuid.uuid4().hex - impersonation = True - - token = fixture.V3Token(trust_id=trust_id, - trustee_user_id=trustee_user_id, - trustor_user_id=trustor_user_id, - trust_impersonation=impersonation) - - trust = token['token']['OS-TRUST:trust'] - self.assertEqual(trust_id, token.trust_id) - self.assertEqual(trust_id, trust['id']) - self.assertEqual(trustee_user_id, token.trustee_user_id) - self.assertEqual(trustee_user_id, trust['trustee_user']['id']) - self.assertEqual(trustor_user_id, token.trustor_user_id) - self.assertEqual(trustor_user_id, trust['trustor_user']['id']) - self.assertEqual(impersonation, token.trust_impersonation) - self.assertEqual(impersonation, trust['impersonation']) - - def test_oauth_scoped(self): - access_id = uuid.uuid4().hex - consumer_id = uuid.uuid4().hex - - token = fixture.V3Token(oauth_access_token_id=access_id, - oauth_consumer_id=consumer_id) - - oauth = token['token']['OS-OAUTH1'] - - self.assertEqual(access_id, token.oauth_access_token_id) - self.assertEqual(access_id, oauth['access_token_id']) - self.assertEqual(consumer_id, token.oauth_consumer_id) - self.assertEqual(consumer_id, oauth['consumer_id']) - - def test_catalog(self): - service_type = uuid.uuid4().hex - service_name = uuid.uuid4().hex - service_id = uuid.uuid4().hex - region = uuid.uuid4().hex - endpoints = {'public': uuid.uuid4().hex, - 'internal': uuid.uuid4().hex, - 'admin': uuid.uuid4().hex} - - token = fixture.V3Token() - svc = token.add_service(type=service_type, - name=service_name, - id=service_id) - svc.add_standard_endpoints(region=region, **endpoints) - - self.assertEqual(1, len(token['token']['catalog'])) - service = token['token']['catalog'][0] - self.assertEqual(3, len(service['endpoints'])) - - self.assertEqual(service_name, service['name']) - self.assertEqual(service_type, service['type']) - self.assertEqual(service_id, service['id']) - - for endpoint in service['endpoints']: - # assert an id exists for each endpoint, remove it to make testing - # the endpoint content below easier. - self.assertTrue(endpoint.pop('id')) - - for interface, url in endpoints.items(): - endpoint = {'interface': interface, 'url': url, - 'region': region, 'region_id': region} - self.assertIn(endpoint, service['endpoints']) diff --git a/keystoneclient/tests/unit/test_http.py b/keystoneclient/tests/unit/test_http.py deleted file mode 100644 index af9058f9..00000000 --- a/keystoneclient/tests/unit/test_http.py +++ /dev/null @@ -1,218 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -import six -from testtools import matchers - -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient import session -from keystoneclient.tests.unit import utils - - -RESPONSE_BODY = '{"hi": "there"}' - - -def get_client(): - cl = httpclient.HTTPClient(username="username", password="password", - project_id="tenant", auth_url="auth_test") - return cl - - -def get_authed_client(): - cl = get_client() - cl.management_url = "http://127.0.0.1:5000" - cl.auth_token = "token" - return cl - - -class ClientTest(utils.TestCase): - - TEST_URL = 'http://127.0.0.1:5000/hi' - - def test_unauthorized_client_requests(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_client() - self.assertRaises(exceptions.AuthorizationFailure, cl.get, '/hi') - self.assertRaises(exceptions.AuthorizationFailure, cl.post, '/hi') - self.assertRaises(exceptions.AuthorizationFailure, cl.put, '/hi') - self.assertRaises(exceptions.AuthorizationFailure, cl.delete, '/hi') - - def test_get(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - self.stub_url('GET', text=RESPONSE_BODY) - - with self.deprecations.expect_deprecations_here(): - resp, body = cl.get("/hi") - self.assertEqual(self.requests_mock.last_request.method, 'GET') - self.assertEqual(self.requests_mock.last_request.url, self.TEST_URL) - - self.assertRequestHeaderEqual('X-Auth-Token', 'token') - self.assertRequestHeaderEqual('User-Agent', httpclient.USER_AGENT) - - # Automatic JSON parsing - self.assertEqual(body, {"hi": "there"}) - - def test_get_error_with_plaintext_resp(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - self.stub_url('GET', status_code=400, - text='Some evil plaintext string') - - self.assertRaises(exceptions.BadRequest, cl.get, '/hi') - - def test_get_error_with_json_resp(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - err_response = { - "error": { - "code": 400, - "title": "Error title", - "message": "Error message string" - } - } - self.stub_url('GET', status_code=400, json=err_response) - exc_raised = False - try: - with self.deprecations.expect_deprecations_here(): - cl.get('/hi') - except exceptions.BadRequest as exc: - exc_raised = True - self.assertEqual(exc.message, "Error message string (HTTP 400)") - self.assertTrue(exc_raised, 'Exception not raised.') - - def test_post(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - self.stub_url('POST') - with self.deprecations.expect_deprecations_here(): - cl.post("/hi", body=[1, 2, 3]) - - self.assertEqual(self.requests_mock.last_request.method, 'POST') - self.assertEqual(self.requests_mock.last_request.body, '[1, 2, 3]') - - self.assertRequestHeaderEqual('X-Auth-Token', 'token') - self.assertRequestHeaderEqual('Content-Type', 'application/json') - self.assertRequestHeaderEqual('User-Agent', httpclient.USER_AGENT) - - def test_forwarded_for(self): - ORIGINAL_IP = "10.100.100.1" - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username="username", - password="password", - project_id="tenant", - auth_url="auth_test", - original_ip=ORIGINAL_IP) - - self.stub_url('GET') - - with self.deprecations.expect_deprecations_here(): - cl.request(self.TEST_URL, 'GET') - forwarded = "for=%s;by=%s" % (ORIGINAL_IP, httpclient.USER_AGENT) - self.assertRequestHeaderEqual('Forwarded', forwarded) - - def test_client_deprecated(self): - # Can resolve symbols from the keystoneclient.client module. - # keystoneclient.client was deprecated and renamed to - # keystoneclient.httpclient. This tests that keystoneclient.client - # can still be used. - - from keystoneclient import client - - # These statements will raise an AttributeError if the symbol isn't - # defined in the module. - - client.HTTPClient - - -class BasicRequestTests(utils.TestCase): - - url = 'http://keystone.test.com/' - - def setUp(self): - super(BasicRequestTests, self).setUp() - self.logger_message = six.moves.cStringIO() - handler = logging.StreamHandler(self.logger_message) - handler.setLevel(logging.DEBUG) - - self.logger = logging.getLogger(session.__name__) - level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.DEBUG) - self.logger.addHandler(handler) - - self.addCleanup(self.logger.removeHandler, handler) - self.addCleanup(self.logger.setLevel, level) - - def request(self, method='GET', response='Test Response', status_code=200, - url=None, headers={}, **kwargs): - if not url: - url = self.url - - self.requests_mock.register_uri(method, url, text=response, - status_code=status_code, - headers=headers) - - with self.deprecations.expect_deprecations_here(): - return httpclient.request(url, method, headers=headers, **kwargs) - - def test_basic_params(self): - method = 'GET' - response = 'Test Response' - status = 200 - - self.request(method=method, status_code=status, response=response, - headers={'Content-Type': 'application/json'}) - - self.assertEqual(self.requests_mock.last_request.method, method) - - logger_message = self.logger_message.getvalue() - - self.assertThat(logger_message, matchers.Contains('curl')) - self.assertThat(logger_message, matchers.Contains('-X %s' % - method)) - self.assertThat(logger_message, matchers.Contains(self.url)) - - self.assertThat(logger_message, matchers.Contains(str(status))) - self.assertThat(logger_message, matchers.Contains(response)) - - def test_headers(self): - headers = {'key': 'val', 'test': 'other'} - - self.request(headers=headers) - - for k, v in headers.items(): - self.assertRequestHeaderEqual(k, v) - - for header in headers.items(): - self.assertThat(self.logger_message.getvalue(), - matchers.Contains('-H "%s: %s"' % header)) - - def test_body(self): - data = "BODY DATA" - self.request(response=data, - headers={'Content-Type': 'application/json'}) - logger_message = self.logger_message.getvalue() - self.assertThat(logger_message, matchers.Contains('BODY:')) - self.assertThat(logger_message, matchers.Contains(data)) diff --git a/keystoneclient/tests/unit/test_https.py b/keystoneclient/tests/unit/test_https.py deleted file mode 100644 index 4e8d260c..00000000 --- a/keystoneclient/tests/unit/test_https.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import requests - -from keystoneclient import httpclient -from keystoneclient.tests.unit import utils - - -FAKE_RESPONSE = utils.test_response(json={'hi': 'there'}) - -REQUEST_URL = 'https://127.0.0.1:5000/hi' -RESPONSE_BODY = '{"hi": "there"}' - - -def get_client(): - cl = httpclient.HTTPClient(username="username", password="password", - project_id="tenant", auth_url="auth_test", - cacert="ca.pem", cert=('cert.pem', "key.pem")) - return cl - - -def get_authed_client(): - cl = get_client() - cl.management_url = "https://127.0.0.1:5000" - cl.auth_token = "token" - return cl - - -class ClientTest(utils.TestCase): - - @mock.patch.object(requests, 'request') - def test_get(self, MOCK_REQUEST): - MOCK_REQUEST.return_value = FAKE_RESPONSE - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - with self.deprecations.expect_deprecations_here(): - resp, body = cl.get("/hi") - - # this may become too tightly couple later - mock_args, mock_kwargs = MOCK_REQUEST.call_args - - self.assertEqual(mock_args[0], 'GET') - self.assertEqual(mock_args[1], REQUEST_URL) - self.assertEqual(mock_kwargs['headers']['X-Auth-Token'], 'token') - self.assertEqual(mock_kwargs['cert'], ('cert.pem', 'key.pem')) - self.assertEqual(mock_kwargs['verify'], 'ca.pem') - - # Automatic JSON parsing - self.assertEqual(body, {"hi": "there"}) - - @mock.patch.object(requests, 'request') - def test_post(self, MOCK_REQUEST): - MOCK_REQUEST.return_value = FAKE_RESPONSE - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = get_authed_client() - - with self.deprecations.expect_deprecations_here(): - cl.post("/hi", body=[1, 2, 3]) - - # this may become too tightly couple later - mock_args, mock_kwargs = MOCK_REQUEST.call_args - - self.assertEqual(mock_args[0], 'POST') - self.assertEqual(mock_args[1], REQUEST_URL) - self.assertEqual(mock_kwargs['data'], '[1, 2, 3]') - self.assertEqual(mock_kwargs['headers']['X-Auth-Token'], 'token') - self.assertEqual(mock_kwargs['cert'], ('cert.pem', 'key.pem')) - self.assertEqual(mock_kwargs['verify'], 'ca.pem') - - @mock.patch.object(requests, 'request') - def test_post_auth(self, MOCK_REQUEST): - MOCK_REQUEST.return_value = FAKE_RESPONSE - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient( - username="username", password="password", project_id="tenant", - auth_url="auth_test", cacert="ca.pem", - cert=('cert.pem', 'key.pem')) - cl.management_url = "https://127.0.0.1:5000" - cl.auth_token = "token" - with self.deprecations.expect_deprecations_here(): - cl.post("/hi", body=[1, 2, 3]) - - # this may become too tightly couple later - mock_args, mock_kwargs = MOCK_REQUEST.call_args - - self.assertEqual(mock_args[0], 'POST') - self.assertEqual(mock_args[1], REQUEST_URL) - self.assertEqual(mock_kwargs['data'], '[1, 2, 3]') - self.assertEqual(mock_kwargs['headers']['X-Auth-Token'], 'token') - self.assertEqual(mock_kwargs['cert'], ('cert.pem', 'key.pem')) - self.assertEqual(mock_kwargs['verify'], 'ca.pem') diff --git a/keystoneclient/tests/unit/test_keyring.py b/keystoneclient/tests/unit/test_keyring.py deleted file mode 100644 index 7d30d980..00000000 --- a/keystoneclient/tests/unit/test_keyring.py +++ /dev/null @@ -1,201 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime - -import mock -from oslo_utils import timeutils - -from keystoneclient import access -from keystoneclient import httpclient -from keystoneclient.tests.unit import utils -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient import utils as client_utils - -try: - import keyring # noqa - import pickle # noqa -except ImportError: - keyring = None - - -PROJECT_SCOPED_TOKEN = client_fixtures.project_scoped_token() - -# These mirror values from PROJECT_SCOPED_TOKEN -USERNAME = 'exampleuser' -AUTH_URL = 'http://public.com:5000/v2.0' -TOKEN = '04c7d5ffaeef485f9dc69c06db285bdb' - -PASSWORD = 'password' -TENANT = 'tenant' -TENANT_ID = 'tenant_id' - - -class KeyringTest(utils.TestCase): - - def setUp(self): - if keyring is None: - self.skipTest( - 'optional package keyring or pickle is not installed') - - class MemoryKeyring(keyring.backend.KeyringBackend): - """A Simple testing keyring. - - This class supports stubbing an initial password to be returned by - setting password, and allows easy password and key retrieval. Also - records if a password was retrieved. - """ - - def __init__(self): - self.key = None - self.password = None - self.fetched = False - self.get_password_called = False - self.set_password_called = False - - def supported(self): - return 1 - - def get_password(self, service, username): - self.get_password_called = True - key = username + '@' + service - # make sure we don't get passwords crossed if one is enforced. - if self.key and self.key != key: - return None - if self.password: - self.fetched = True - return self.password - - def set_password(self, service, username, password): - self.set_password_called = True - self.key = username + '@' + service - self.password = password - - super(KeyringTest, self).setUp() - self.memory_keyring = MemoryKeyring() - keyring.set_keyring(self.memory_keyring) - - def test_no_keyring_key(self): - """Test case when no keyring set. - - Ensure that if we don't have use_keyring set in the client that - the keyring is never accessed. - """ - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL) - - # stub and check that a new token is received - method = 'get_raw_token_from_identity_service' - with mock.patch.object(cl, method) as meth: - meth.return_value = (True, PROJECT_SCOPED_TOKEN) - - self.assertTrue(cl.authenticate()) - - self.assertEqual(1, meth.call_count) - - # make sure that we never touched the keyring - self.assertFalse(self.memory_keyring.get_password_called) - self.assertFalse(self.memory_keyring.set_password_called) - - def test_build_keyring_key(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL) - - keyring_key = cl._build_keyring_key(auth_url=AUTH_URL, - username=USERNAME, - tenant_name=TENANT, - tenant_id=TENANT_ID, - token=TOKEN) - - self.assertEqual(keyring_key, - '%s/%s/%s/%s/%s' % - (AUTH_URL, TENANT_ID, TENANT, TOKEN, USERNAME)) - - def test_set_and_get_keyring_expired(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) - - # set an expired token into the keyring - auth_ref = access.AccessInfo.factory(body=PROJECT_SCOPED_TOKEN) - expired = timeutils.utcnow() - datetime.timedelta(minutes=30) - auth_ref['token']['expires'] = client_utils.isotime(expired) - self.memory_keyring.password = pickle.dumps(auth_ref) - - # stub and check that a new token is received, so not using expired - method = 'get_raw_token_from_identity_service' - with mock.patch.object(cl, method) as meth: - meth.return_value = (True, PROJECT_SCOPED_TOKEN) - - self.assertTrue(cl.authenticate()) - - self.assertEqual(1, meth.call_count) - - # check that a value was returned from the keyring - self.assertTrue(self.memory_keyring.fetched) - - # check that the new token has been loaded into the keyring - new_auth_ref = pickle.loads(self.memory_keyring.password) - self.assertEqual(new_auth_ref['token']['expires'], - PROJECT_SCOPED_TOKEN['access']['token']['expires']) - - def test_get_keyring(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) - - # set an token into the keyring - auth_ref = access.AccessInfo.factory(body=PROJECT_SCOPED_TOKEN) - future = timeutils.utcnow() + datetime.timedelta(minutes=30) - auth_ref['token']['expires'] = client_utils.isotime(future) - self.memory_keyring.password = pickle.dumps(auth_ref) - - # don't stub get_raw_token so will fail if authenticate happens - - self.assertTrue(cl.authenticate()) - self.assertTrue(self.memory_keyring.fetched) - - def test_set_keyring(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - project_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) - - # stub and check that a new token is received - method = 'get_raw_token_from_identity_service' - with mock.patch.object(cl, method) as meth: - meth.return_value = (True, PROJECT_SCOPED_TOKEN) - - self.assertTrue(cl.authenticate()) - - self.assertEqual(1, meth.call_count) - - # we checked the keyring, but we didn't find anything - self.assertTrue(self.memory_keyring.get_password_called) - self.assertFalse(self.memory_keyring.fetched) - - # check that the new token has been loaded into the keyring - self.assertTrue(self.memory_keyring.set_password_called) - new_auth_ref = pickle.loads(self.memory_keyring.password) - self.assertEqual(new_auth_ref.auth_token, TOKEN) - self.assertEqual(new_auth_ref['token'], - PROJECT_SCOPED_TOKEN['access']['token']) - self.assertEqual(new_auth_ref.username, USERNAME) diff --git a/keystoneclient/tests/unit/test_session.py b/keystoneclient/tests/unit/test_session.py deleted file mode 100644 index 27d224d0..00000000 --- a/keystoneclient/tests/unit/test_session.py +++ /dev/null @@ -1,1127 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import itertools -import logging -import uuid - -import mock -from oslo_config import cfg -from oslo_config import fixture as config -from oslo_serialization import jsonutils -import requests -import six -from testtools import matchers - -from keystoneclient import adapter -from keystoneclient.auth import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import session as client_session -from keystoneclient.tests.unit import utils - - -class SessionTests(utils.TestCase): - - TEST_URL = 'http://127.0.0.1:5000/' - - def setUp(self): - super(SessionTests, self).setUp() - self.deprecations.expect_deprecations() - - def test_get(self): - session = client_session.Session() - self.stub_url('GET', text='response') - resp = session.get(self.TEST_URL) - - self.assertEqual('GET', self.requests_mock.last_request.method) - self.assertEqual(resp.text, 'response') - self.assertTrue(resp.ok) - - def test_post(self): - session = client_session.Session() - self.stub_url('POST', text='response') - resp = session.post(self.TEST_URL, json={'hello': 'world'}) - - self.assertEqual('POST', self.requests_mock.last_request.method) - self.assertEqual(resp.text, 'response') - self.assertTrue(resp.ok) - self.assertRequestBodyIs(json={'hello': 'world'}) - - def test_head(self): - session = client_session.Session() - self.stub_url('HEAD') - resp = session.head(self.TEST_URL) - - self.assertEqual('HEAD', self.requests_mock.last_request.method) - self.assertTrue(resp.ok) - self.assertRequestBodyIs('') - - def test_put(self): - session = client_session.Session() - self.stub_url('PUT', text='response') - resp = session.put(self.TEST_URL, json={'hello': 'world'}) - - self.assertEqual('PUT', self.requests_mock.last_request.method) - self.assertEqual(resp.text, 'response') - self.assertTrue(resp.ok) - self.assertRequestBodyIs(json={'hello': 'world'}) - - def test_delete(self): - session = client_session.Session() - self.stub_url('DELETE', text='response') - resp = session.delete(self.TEST_URL) - - self.assertEqual('DELETE', self.requests_mock.last_request.method) - self.assertTrue(resp.ok) - self.assertEqual(resp.text, 'response') - - def test_patch(self): - session = client_session.Session() - self.stub_url('PATCH', text='response') - resp = session.patch(self.TEST_URL, json={'hello': 'world'}) - - self.assertEqual('PATCH', self.requests_mock.last_request.method) - self.assertTrue(resp.ok) - self.assertEqual(resp.text, 'response') - self.assertRequestBodyIs(json={'hello': 'world'}) - - def test_user_agent(self): - session = client_session.Session(user_agent='test-agent') - self.stub_url('GET', text='response') - resp = session.get(self.TEST_URL) - - self.assertTrue(resp.ok) - self.assertRequestHeaderEqual('User-Agent', 'test-agent') - - resp = session.get(self.TEST_URL, headers={'User-Agent': 'new-agent'}) - self.assertTrue(resp.ok) - self.assertRequestHeaderEqual('User-Agent', 'new-agent') - - resp = session.get(self.TEST_URL, headers={'User-Agent': 'new-agent'}, - user_agent='overrides-agent') - self.assertTrue(resp.ok) - self.assertRequestHeaderEqual('User-Agent', 'overrides-agent') - - def test_http_session_opts(self): - session = client_session.Session(cert='cert.pem', timeout=5, - verify='certs') - - FAKE_RESP = utils.test_response(text='resp') - RESP = mock.Mock(return_value=FAKE_RESP) - - with mock.patch.object(session.session, 'request', RESP) as mocked: - session.post(self.TEST_URL, data='value') - - mock_args, mock_kwargs = mocked.call_args - - self.assertEqual(mock_args[0], 'POST') - self.assertEqual(mock_args[1], self.TEST_URL) - self.assertEqual(mock_kwargs['data'], 'value') - self.assertEqual(mock_kwargs['cert'], 'cert.pem') - self.assertEqual(mock_kwargs['verify'], 'certs') - self.assertEqual(mock_kwargs['timeout'], 5) - - def test_not_found(self): - session = client_session.Session() - self.stub_url('GET', status_code=404) - self.assertRaises(exceptions.NotFound, session.get, self.TEST_URL) - - def test_server_error(self): - session = client_session.Session() - self.stub_url('GET', status_code=500) - self.assertRaises(exceptions.InternalServerError, - session.get, self.TEST_URL) - - def test_session_debug_output(self): - """Test request and response headers in debug logs. - - in order to redact secure headers while debug is true. - """ - session = client_session.Session(verify=False) - headers = {'HEADERA': 'HEADERVALB', - 'Content-Type': 'application/json'} - security_headers = {'Authorization': uuid.uuid4().hex, - 'X-Auth-Token': uuid.uuid4().hex, - 'X-Subject-Token': uuid.uuid4().hex, - 'X-Service-Token': uuid.uuid4().hex} - body = '{"a": "b"}' - data = '{"c": "d"}' - all_headers = dict( - itertools.chain(headers.items(), security_headers.items())) - self.stub_url('POST', text=body, headers=all_headers) - resp = session.post(self.TEST_URL, headers=all_headers, data=data) - self.assertEqual(resp.status_code, 200) - - self.assertIn('curl', self.logger.output) - self.assertIn('POST', self.logger.output) - self.assertIn('--insecure', self.logger.output) - self.assertIn(body, self.logger.output) - self.assertIn("'%s'" % data, self.logger.output) - - for k, v in headers.items(): - self.assertIn(k, self.logger.output) - self.assertIn(v, self.logger.output) - - # Assert that response headers contains actual values and - # only debug logs has been masked - for k, v in security_headers.items(): - self.assertIn('%s: {SHA1}' % k, self.logger.output) - self.assertEqual(v, resp.headers[k]) - self.assertNotIn(v, self.logger.output) - - def test_logs_failed_output(self): - """Test that output is logged even for failed requests.""" - session = client_session.Session() - body = {uuid.uuid4().hex: uuid.uuid4().hex} - - self.stub_url('GET', json=body, status_code=400, - headers={'Content-Type': 'application/json'}) - resp = session.get(self.TEST_URL, raise_exc=False) - - self.assertEqual(resp.status_code, 400) - self.assertIn(list(body.keys())[0], self.logger.output) - self.assertIn(list(body.values())[0], self.logger.output) - - def test_logging_body_only_for_specified_content_types(self): - """Verify response body is only logged in specific content types. - - Response bodies are logged only when the response's Content-Type header - is set to application/json. This prevents us to get an unexpected - MemoryError when reading arbitrary responses, such as streams. - """ - OMITTED_BODY = ('Omitted, Content-Type is set to %s. Only ' - 'application/json responses have their bodies logged.') - session = client_session.Session(verify=False) - - # Content-Type is not set - body = jsonutils.dumps({'token': {'id': '...'}}) - self.stub_url('POST', text=body) - session.post(self.TEST_URL) - self.assertNotIn(body, self.logger.output) - self.assertIn(OMITTED_BODY % None, self.logger.output) - - # Content-Type is set to text/xml - body = '...' - self.stub_url('POST', text=body, headers={'Content-Type': 'text/xml'}) - session.post(self.TEST_URL) - self.assertNotIn(body, self.logger.output) - self.assertIn(OMITTED_BODY % 'text/xml', self.logger.output) - - # Content-Type is set to application/json - body = jsonutils.dumps({'token': {'id': '...'}}) - self.stub_url('POST', text=body, - headers={'Content-Type': 'application/json'}) - session.post(self.TEST_URL) - self.assertIn(body, self.logger.output) - self.assertNotIn(OMITTED_BODY % 'application/json', self.logger.output) - - # Content-Type is set to application/json; charset=UTF-8 - body = jsonutils.dumps({'token': {'id': '...'}}) - self.stub_url( - 'POST', text=body, - headers={'Content-Type': 'application/json; charset=UTF-8'}) - session.post(self.TEST_URL) - self.assertIn(body, self.logger.output) - self.assertNotIn(OMITTED_BODY % 'application/json; charset=UTF-8', - self.logger.output) - - def test_unicode_data_in_debug_output(self): - """Verify that ascii-encodable data is logged without modification.""" - session = client_session.Session(verify=False) - - body = 'RESP' - data = u'αβγδ' - self.stub_url('POST', text=body) - session.post(self.TEST_URL, data=data) - - self.assertIn("'%s'" % data, self.logger.output) - - def test_binary_data_not_in_debug_output(self): - """Verify that non-ascii-encodable data causes replacement.""" - if six.PY2: - data = "my data" + chr(255) - else: - # Python 3 logging handles binary data well. - return - - session = client_session.Session(verify=False) - - body = 'RESP' - self.stub_url('POST', text=body) - - # Forced mixed unicode and byte strings in request - # elements to make sure that all joins are appropriately - # handled (any join of unicode and byte strings should - # raise a UnicodeDecodeError) - session.post(unicode(self.TEST_URL), data=data) - - self.assertNotIn('my data', self.logger.output) - - def test_logging_cacerts(self): - path_to_certs = '/path/to/certs' - session = client_session.Session(verify=path_to_certs) - - self.stub_url('GET', text='text') - session.get(self.TEST_URL) - - self.assertIn('--cacert', self.logger.output) - self.assertIn(path_to_certs, self.logger.output) - - def test_connect_retries(self): - - def _timeout_error(request, context): - raise requests.exceptions.Timeout() - - self.stub_url('GET', text=_timeout_error) - - session = client_session.Session() - retries = 3 - - with mock.patch('time.sleep') as m: - self.assertRaises(exceptions.RequestTimeout, - session.get, - self.TEST_URL, connect_retries=retries) - - self.assertEqual(retries, m.call_count) - # 3 retries finishing with 2.0 means 0.5, 1.0 and 2.0 - m.assert_called_with(2.0) - - # we count retries so there will be one initial request + 3 retries - self.assertThat(self.requests_mock.request_history, - matchers.HasLength(retries + 1)) - - def test_uses_tcp_keepalive_by_default(self): - session = client_session.Session() - requests_session = session.session - self.assertIsInstance(requests_session.adapters['http://'], - client_session.TCPKeepAliveAdapter) - self.assertIsInstance(requests_session.adapters['https://'], - client_session.TCPKeepAliveAdapter) - - def test_does_not_set_tcp_keepalive_on_custom_sessions(self): - mock_session = mock.Mock() - client_session.Session(session=mock_session) - self.assertFalse(mock_session.mount.called) - - def test_ssl_error_message(self): - error = uuid.uuid4().hex - - def _ssl_error(request, context): - raise requests.exceptions.SSLError(error) - - self.stub_url('GET', text=_ssl_error) - session = client_session.Session() - - # The exception should contain the URL and details about the SSL error - msg = _('SSL exception connecting to %(url)s: %(error)s') % { - 'url': self.TEST_URL, 'error': error} - six.assertRaisesRegex(self, - exceptions.SSLError, - msg, - session.get, - self.TEST_URL) - - def test_mask_password_in_http_log_response(self): - session = client_session.Session() - - def fake_debug(msg): - self.assertNotIn('verybadpass', msg) - - logger = mock.Mock(isEnabledFor=mock.Mock(return_value=True)) - logger.debug = mock.Mock(side_effect=fake_debug) - body = { - "connection_info": { - "driver_volume_type": "iscsi", - "data": { - "auth_password": "verybadpass", - "target_discovered": False, - "encrypted": False, - "qos_specs": None, - "target_iqn": ("iqn.2010-10.org.openstack:volume-" - "744d2085-8e78-40a5-8659-ef3cffb2480e"), - "target_portal": "172.99.69.228:3260", - "volume_id": "744d2085-8e78-40a5-8659-ef3cffb2480e", - "target_lun": 1, - "access_mode": "rw", - "auth_username": "verybadusername", - "auth_method": "CHAP"}}} - body_json = jsonutils.dumps(body) - response = mock.Mock(text=body_json, status_code=200, - headers={'content-type': 'application/json'}) - session._http_log_response(response, logger) - self.assertEqual(1, logger.debug.call_count) - - -class TCPKeepAliveAdapter(utils.TestCase): - - @mock.patch.object(client_session, 'socket') - @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') - def test_init_poolmanager_all_options(self, mock_parent_init_poolmanager, - mock_socket): - # properties expected to be in socket. - mock_socket.TCP_KEEPIDLE = mock.sentinel.TCP_KEEPIDLE - mock_socket.TCP_KEEPCNT = mock.sentinel.TCP_KEEPCNT - mock_socket.TCP_KEEPINTVL = mock.sentinel.TCP_KEEPINTVL - desired_opts = [mock_socket.TCP_KEEPIDLE, mock_socket.TCP_KEEPCNT, - mock_socket.TCP_KEEPINTVL] - - adapter = client_session.TCPKeepAliveAdapter() - adapter.init_poolmanager() - - call_args, call_kwargs = mock_parent_init_poolmanager.call_args - called_socket_opts = call_kwargs['socket_options'] - call_options = [opt for (protocol, opt, value) in called_socket_opts] - for opt in desired_opts: - self.assertIn(opt, call_options) - - @mock.patch.object(client_session, 'socket') - @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') - def test_init_poolmanager(self, mock_parent_init_poolmanager, mock_socket): - spec = ['IPPROTO_TCP', 'TCP_NODELAY', 'SOL_SOCKET', 'SO_KEEPALIVE'] - mock_socket.mock_add_spec(spec) - adapter = client_session.TCPKeepAliveAdapter() - adapter.init_poolmanager() - - call_args, call_kwargs = mock_parent_init_poolmanager.call_args - called_socket_opts = call_kwargs['socket_options'] - call_options = [opt for (protocol, opt, value) in called_socket_opts] - self.assertEqual([mock_socket.TCP_NODELAY, mock_socket.SO_KEEPALIVE], - call_options) - - -class RedirectTests(utils.TestCase): - - REDIRECT_CHAIN = ['http://myhost:3445/', - 'http://anotherhost:6555/', - 'http://thirdhost/', - 'http://finaldestination:55/'] - - DEFAULT_REDIRECT_BODY = 'Redirect' - DEFAULT_RESP_BODY = 'Found' - - def setUp(self): - super(RedirectTests, self).setUp() - self.deprecations.expect_deprecations() - - def setup_redirects(self, method='GET', status_code=305, - redirect_kwargs=None, final_kwargs=None): - redirect_kwargs = redirect_kwargs or {} - final_kwargs = final_kwargs or {} - redirect_kwargs.setdefault('text', self.DEFAULT_REDIRECT_BODY) - - for s, d in zip(self.REDIRECT_CHAIN, self.REDIRECT_CHAIN[1:]): - self.requests_mock.register_uri(method, s, status_code=status_code, - headers={'Location': d}, - **redirect_kwargs) - - final_kwargs.setdefault('status_code', 200) - final_kwargs.setdefault('text', self.DEFAULT_RESP_BODY) - self.requests_mock.register_uri(method, self.REDIRECT_CHAIN[-1], - **final_kwargs) - - def assertResponse(self, resp): - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.text, self.DEFAULT_RESP_BODY) - - def test_basic_get(self): - session = client_session.Session() - self.setup_redirects() - resp = session.get(self.REDIRECT_CHAIN[-2]) - self.assertResponse(resp) - - def test_basic_post_keeps_correct_method(self): - session = client_session.Session() - self.setup_redirects(method='POST', status_code=301) - resp = session.post(self.REDIRECT_CHAIN[-2]) - self.assertResponse(resp) - - def test_redirect_forever(self): - session = client_session.Session(redirect=True) - self.setup_redirects() - resp = session.get(self.REDIRECT_CHAIN[0]) - self.assertResponse(resp) - self.assertTrue(len(resp.history), len(self.REDIRECT_CHAIN)) - - def test_no_redirect(self): - session = client_session.Session(redirect=False) - self.setup_redirects() - resp = session.get(self.REDIRECT_CHAIN[0]) - self.assertEqual(resp.status_code, 305) - self.assertEqual(resp.url, self.REDIRECT_CHAIN[0]) - - def test_redirect_limit(self): - self.setup_redirects() - for i in (1, 2): - session = client_session.Session(redirect=i) - resp = session.get(self.REDIRECT_CHAIN[0]) - self.assertEqual(resp.status_code, 305) - self.assertEqual(resp.url, self.REDIRECT_CHAIN[i]) - self.assertEqual(resp.text, self.DEFAULT_REDIRECT_BODY) - - def test_history_matches_requests(self): - self.setup_redirects(status_code=301) - session = client_session.Session(redirect=True) - req_resp = requests.get(self.REDIRECT_CHAIN[0], - allow_redirects=True) - - ses_resp = session.get(self.REDIRECT_CHAIN[0]) - - self.assertEqual(len(req_resp.history), len(ses_resp.history)) - - for r, s in zip(req_resp.history, ses_resp.history): - self.assertEqual(r.url, s.url) - self.assertEqual(r.status_code, s.status_code) - - -class ConstructSessionFromArgsTests(utils.TestCase): - - KEY = 'keyfile' - CERT = 'certfile' - CACERT = 'cacert-path' - - def _s(self, k=None, **kwargs): - k = k or kwargs - with self.deprecations.expect_deprecations_here(): - return client_session.Session.construct(k) - - def test_verify(self): - self.assertFalse(self._s(insecure=True).verify) - self.assertTrue(self._s(verify=True, insecure=True).verify) - self.assertFalse(self._s(verify=False, insecure=True).verify) - self.assertEqual(self._s(cacert=self.CACERT).verify, self.CACERT) - - def test_cert(self): - tup = (self.CERT, self.KEY) - self.assertEqual(self._s(cert=tup).cert, tup) - self.assertEqual(self._s(cert=self.CERT, key=self.KEY).cert, tup) - self.assertIsNone(self._s(key=self.KEY).cert) - - def test_pass_through(self): - value = 42 # only a number because timeout needs to be - for key in ['timeout', 'session', 'original_ip', 'user_agent']: - args = {key: value} - self.assertEqual(getattr(self._s(args), key), value) - self.assertNotIn(key, args) - - -class AuthPlugin(base.BaseAuthPlugin): - """Very simple debug authentication plugin. - - Takes Parameters such that it can throw exceptions at the right times. - """ - - TEST_TOKEN = utils.TestCase.TEST_TOKEN - TEST_USER_ID = 'aUser' - TEST_PROJECT_ID = 'aProject' - - SERVICE_URLS = { - 'identity': {'public': 'http://identity-public:1111/v2.0', - 'admin': 'http://identity-admin:1111/v2.0'}, - 'compute': {'public': 'http://compute-public:2222/v1.0', - 'admin': 'http://compute-admin:2222/v1.0'}, - 'image': {'public': 'http://image-public:3333/v2.0', - 'admin': 'http://image-admin:3333/v2.0'} - } - - def __init__(self, token=TEST_TOKEN, invalidate=True): - self.token = token - self._invalidate = invalidate - - def get_token(self, session): - return self.token - - def get_endpoint(self, session, service_type=None, interface=None, - **kwargs): - try: - return self.SERVICE_URLS[service_type][interface] - except (KeyError, AttributeError): - return None - - def invalidate(self): - return self._invalidate - - def get_user_id(self, session): - return self.TEST_USER_ID - - def get_project_id(self, session): - return self.TEST_PROJECT_ID - - -class CalledAuthPlugin(base.BaseAuthPlugin): - - ENDPOINT = 'http://fakeendpoint/' - - def __init__(self, invalidate=True): - self.get_token_called = False - self.get_endpoint_called = False - self.endpoint_arguments = {} - self.invalidate_called = False - self._invalidate = invalidate - - def get_token(self, session): - self.get_token_called = True - return utils.TestCase.TEST_TOKEN - - def get_endpoint(self, session, **kwargs): - self.get_endpoint_called = True - self.endpoint_arguments = kwargs - return self.ENDPOINT - - def invalidate(self): - self.invalidate_called = True - return self._invalidate - - -class SessionAuthTests(utils.TestCase): - - TEST_URL = 'http://127.0.0.1:5000/' - TEST_JSON = {'hello': 'world'} - - def setUp(self): - super(SessionAuthTests, self).setUp() - self.deprecations.expect_deprecations() - - def stub_service_url(self, service_type, interface, path, - method='GET', **kwargs): - base_url = AuthPlugin.SERVICE_URLS[service_type][interface] - uri = "%s/%s" % (base_url.rstrip('/'), path.lstrip('/')) - - self.requests_mock.register_uri(method, uri, **kwargs) - - def test_auth_plugin_default_with_plugin(self): - self.stub_url('GET', base_url=self.TEST_URL, json=self.TEST_JSON) - - # if there is an auth_plugin then it should default to authenticated - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - resp = sess.get(self.TEST_URL) - self.assertEqual(resp.json(), self.TEST_JSON) - - self.assertRequestHeaderEqual('X-Auth-Token', AuthPlugin.TEST_TOKEN) - - def test_auth_plugin_disable(self): - self.stub_url('GET', base_url=self.TEST_URL, json=self.TEST_JSON) - - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - resp = sess.get(self.TEST_URL, authenticated=False) - self.assertEqual(resp.json(), self.TEST_JSON) - - self.assertRequestHeaderEqual('X-Auth-Token', None) - - def test_service_type_urls(self): - service_type = 'compute' - interface = 'public' - path = '/instances' - status = 200 - body = 'SUCCESS' - - self.stub_service_url(service_type=service_type, - interface=interface, - path=path, - status_code=status, - text=body) - - sess = client_session.Session(auth=AuthPlugin()) - resp = sess.get(path, - endpoint_filter={'service_type': service_type, - 'interface': interface}) - - self.assertEqual(self.requests_mock.last_request.url, - AuthPlugin.SERVICE_URLS['compute']['public'] + path) - self.assertEqual(resp.text, body) - self.assertEqual(resp.status_code, status) - - def test_service_url_raises_if_no_auth_plugin(self): - sess = client_session.Session() - self.assertRaises(exceptions.MissingAuthPlugin, - sess.get, '/path', - endpoint_filter={'service_type': 'compute', - 'interface': 'public'}) - - def test_service_url_raises_if_no_url_returned(self): - sess = client_session.Session(auth=AuthPlugin()) - self.assertRaises(exceptions.EndpointNotFound, - sess.get, '/path', - endpoint_filter={'service_type': 'unknown', - 'interface': 'public'}) - - def test_raises_exc_only_when_asked(self): - # A request that returns a HTTP error should by default raise an - # exception by default, if you specify raise_exc=False then it will not - self.requests_mock.get(self.TEST_URL, status_code=401) - - sess = client_session.Session() - self.assertRaises(exceptions.Unauthorized, sess.get, self.TEST_URL) - - resp = sess.get(self.TEST_URL, raise_exc=False) - self.assertEqual(401, resp.status_code) - - def test_passed_auth_plugin(self): - passed = CalledAuthPlugin() - sess = client_session.Session() - - self.requests_mock.get(CalledAuthPlugin.ENDPOINT + 'path', - status_code=200) - endpoint_filter = {'service_type': 'identity'} - - # no plugin with authenticated won't work - self.assertRaises(exceptions.MissingAuthPlugin, sess.get, 'path', - authenticated=True) - - # no plugin with an endpoint filter won't work - self.assertRaises(exceptions.MissingAuthPlugin, sess.get, 'path', - authenticated=False, endpoint_filter=endpoint_filter) - - resp = sess.get('path', auth=passed, endpoint_filter=endpoint_filter) - - self.assertEqual(200, resp.status_code) - self.assertTrue(passed.get_endpoint_called) - self.assertTrue(passed.get_token_called) - - def test_passed_auth_plugin_overrides(self): - fixed = CalledAuthPlugin() - passed = CalledAuthPlugin() - - sess = client_session.Session(fixed) - - self.requests_mock.get(CalledAuthPlugin.ENDPOINT + 'path', - status_code=200) - - resp = sess.get('path', auth=passed, - endpoint_filter={'service_type': 'identity'}) - - self.assertEqual(200, resp.status_code) - self.assertTrue(passed.get_endpoint_called) - self.assertTrue(passed.get_token_called) - self.assertFalse(fixed.get_endpoint_called) - self.assertFalse(fixed.get_token_called) - - def test_requests_auth_plugin(self): - sess = client_session.Session() - - requests_auth = object() - - FAKE_RESP = utils.test_response(text='resp') - RESP = mock.Mock(return_value=FAKE_RESP) - - with mock.patch.object(sess.session, 'request', RESP) as mocked: - sess.get(self.TEST_URL, requests_auth=requests_auth) - - mocked.assert_called_once_with('GET', self.TEST_URL, - headers=mock.ANY, - allow_redirects=mock.ANY, - auth=requests_auth, - verify=mock.ANY) - - def test_reauth_called(self): - auth = CalledAuthPlugin(invalidate=True) - sess = client_session.Session(auth=auth) - - self.requests_mock.get(self.TEST_URL, - [{'text': 'Failed', 'status_code': 401}, - {'text': 'Hello', 'status_code': 200}]) - - # allow_reauth=True is the default - resp = sess.get(self.TEST_URL, authenticated=True) - - self.assertEqual(200, resp.status_code) - self.assertEqual('Hello', resp.text) - self.assertTrue(auth.invalidate_called) - - def test_reauth_not_called(self): - auth = CalledAuthPlugin(invalidate=True) - sess = client_session.Session(auth=auth) - - self.requests_mock.get(self.TEST_URL, - [{'text': 'Failed', 'status_code': 401}, - {'text': 'Hello', 'status_code': 200}]) - - self.assertRaises(exceptions.Unauthorized, sess.get, self.TEST_URL, - authenticated=True, allow_reauth=False) - self.assertFalse(auth.invalidate_called) - - def test_endpoint_override_overrides_filter(self): - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - - override_base = 'http://mytest/' - path = 'path' - override_url = override_base + path - resp_text = uuid.uuid4().hex - - self.requests_mock.get(override_url, text=resp_text) - - resp = sess.get(path, - endpoint_override=override_base, - endpoint_filter={'service_type': 'identity'}) - - self.assertEqual(resp_text, resp.text) - self.assertEqual(override_url, self.requests_mock.last_request.url) - - self.assertTrue(auth.get_token_called) - self.assertFalse(auth.get_endpoint_called) - - def test_endpoint_override_ignore_full_url(self): - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - - path = 'path' - url = self.TEST_URL + path - - resp_text = uuid.uuid4().hex - self.requests_mock.get(url, text=resp_text) - - resp = sess.get(url, - endpoint_override='http://someother.url', - endpoint_filter={'service_type': 'identity'}) - - self.assertEqual(resp_text, resp.text) - self.assertEqual(url, self.requests_mock.last_request.url) - - self.assertTrue(auth.get_token_called) - self.assertFalse(auth.get_endpoint_called) - - def test_user_and_project_id(self): - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - - self.assertEqual(auth.TEST_USER_ID, sess.get_user_id()) - self.assertEqual(auth.TEST_PROJECT_ID, sess.get_project_id()) - - def test_logger_object_passed(self): - logger = logging.getLogger(uuid.uuid4().hex) - logger.setLevel(logging.DEBUG) - logger.propagate = False - - io = six.StringIO() - handler = logging.StreamHandler(io) - logger.addHandler(handler) - - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - response = {uuid.uuid4().hex: uuid.uuid4().hex} - - self.stub_url('GET', - json=response, - headers={'Content-Type': 'application/json'}) - - resp = sess.get(self.TEST_URL, logger=logger) - - self.assertEqual(response, resp.json()) - output = io.getvalue() - - self.assertIn(self.TEST_URL, output) - self.assertIn(list(response.keys())[0], output) - self.assertIn(list(response.values())[0], output) - - self.assertNotIn(self.TEST_URL, self.logger.output) - self.assertNotIn(list(response.keys())[0], self.logger.output) - self.assertNotIn(list(response.values())[0], self.logger.output) - - -class AdapterTest(utils.TestCase): - - SERVICE_TYPE = uuid.uuid4().hex - SERVICE_NAME = uuid.uuid4().hex - INTERFACE = uuid.uuid4().hex - REGION_NAME = uuid.uuid4().hex - USER_AGENT = uuid.uuid4().hex - VERSION = uuid.uuid4().hex - - TEST_URL = CalledAuthPlugin.ENDPOINT - - def setUp(self): - super(AdapterTest, self).setUp() - self.deprecations.expect_deprecations() - - def _create_loaded_adapter(self): - auth = CalledAuthPlugin() - sess = client_session.Session() - return adapter.Adapter(sess, - auth=auth, - service_type=self.SERVICE_TYPE, - service_name=self.SERVICE_NAME, - interface=self.INTERFACE, - region_name=self.REGION_NAME, - user_agent=self.USER_AGENT, - version=self.VERSION) - - def _verify_endpoint_called(self, adpt): - self.assertEqual(self.SERVICE_TYPE, - adpt.auth.endpoint_arguments['service_type']) - self.assertEqual(self.SERVICE_NAME, - adpt.auth.endpoint_arguments['service_name']) - self.assertEqual(self.INTERFACE, - adpt.auth.endpoint_arguments['interface']) - self.assertEqual(self.REGION_NAME, - adpt.auth.endpoint_arguments['region_name']) - self.assertEqual(self.VERSION, - adpt.auth.endpoint_arguments['version']) - - def test_setting_variables_on_request(self): - response = uuid.uuid4().hex - self.stub_url('GET', text=response) - adpt = self._create_loaded_adapter() - resp = adpt.get('/') - self.assertEqual(resp.text, response) - - self._verify_endpoint_called(adpt) - self.assertTrue(adpt.auth.get_token_called) - self.assertRequestHeaderEqual('User-Agent', self.USER_AGENT) - - def test_setting_variables_on_get_endpoint(self): - adpt = self._create_loaded_adapter() - url = adpt.get_endpoint() - - self.assertEqual(self.TEST_URL, url) - self._verify_endpoint_called(adpt) - - def test_legacy_binding(self): - key = uuid.uuid4().hex - val = uuid.uuid4().hex - response = jsonutils.dumps({key: val}) - - self.stub_url('GET', text=response) - - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.LegacyJsonAdapter(sess, - service_type=self.SERVICE_TYPE, - user_agent=self.USER_AGENT) - - resp, body = adpt.get('/') - self.assertEqual(self.SERVICE_TYPE, - auth.endpoint_arguments['service_type']) - self.assertEqual(resp.text, response) - self.assertEqual(val, body[key]) - - def test_legacy_binding_non_json_resp(self): - response = uuid.uuid4().hex - self.stub_url('GET', text=response, - headers={'Content-Type': 'text/html'}) - - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.LegacyJsonAdapter(sess, - service_type=self.SERVICE_TYPE, - user_agent=self.USER_AGENT) - - resp, body = adpt.get('/') - self.assertEqual(self.SERVICE_TYPE, - auth.endpoint_arguments['service_type']) - self.assertEqual(resp.text, response) - self.assertIsNone(body) - - def test_methods(self): - sess = client_session.Session() - adpt = adapter.Adapter(sess) - url = 'http://url' - - for method in ['get', 'head', 'post', 'put', 'patch', 'delete']: - with mock.patch.object(adpt, 'request') as m: - getattr(adpt, method)(url) - m.assert_called_once_with(url, method.upper()) - - def test_setting_endpoint_override(self): - endpoint_override = 'http://overrideurl' - path = '/path' - endpoint_url = endpoint_override + path - - auth = CalledAuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.Adapter(sess, endpoint_override=endpoint_override) - - response = uuid.uuid4().hex - self.requests_mock.get(endpoint_url, text=response) - - resp = adpt.get(path) - - self.assertEqual(response, resp.text) - self.assertEqual(endpoint_url, self.requests_mock.last_request.url) - - self.assertEqual(endpoint_override, adpt.get_endpoint()) - - def test_adapter_invalidate(self): - auth = CalledAuthPlugin() - sess = client_session.Session() - adpt = adapter.Adapter(sess, auth=auth) - - adpt.invalidate() - - self.assertTrue(auth.invalidate_called) - - def test_adapter_get_token(self): - auth = CalledAuthPlugin() - sess = client_session.Session() - adpt = adapter.Adapter(sess, auth=auth) - - self.assertEqual(self.TEST_TOKEN, adpt.get_token()) - self.assertTrue(auth.get_token_called) - - def test_adapter_connect_retries(self): - retries = 2 - sess = client_session.Session() - adpt = adapter.Adapter(sess, connect_retries=retries) - - def _refused_error(request, context): - raise requests.exceptions.ConnectionError() - - self.stub_url('GET', text=_refused_error) - - with mock.patch('time.sleep') as m: - self.assertRaises(exceptions.ConnectionRefused, - adpt.get, self.TEST_URL) - self.assertEqual(retries, m.call_count) - - # we count retries so there will be one initial request + 2 retries - self.assertThat(self.requests_mock.request_history, - matchers.HasLength(retries + 1)) - - def test_user_and_project_id(self): - auth = AuthPlugin() - sess = client_session.Session() - adpt = adapter.Adapter(sess, auth=auth) - - self.assertEqual(auth.TEST_USER_ID, adpt.get_user_id()) - self.assertEqual(auth.TEST_PROJECT_ID, adpt.get_project_id()) - - def test_logger_object_passed(self): - logger = logging.getLogger(uuid.uuid4().hex) - logger.setLevel(logging.DEBUG) - logger.propagate = False - - io = six.StringIO() - handler = logging.StreamHandler(io) - logger.addHandler(handler) - - auth = AuthPlugin() - sess = client_session.Session(auth=auth) - adpt = adapter.Adapter(sess, auth=auth, logger=logger) - - response = {uuid.uuid4().hex: uuid.uuid4().hex} - - self.stub_url('GET', json=response, - headers={'Content-Type': 'application/json'}) - - resp = adpt.get(self.TEST_URL, logger=logger) - - self.assertEqual(response, resp.json()) - output = io.getvalue() - - self.assertIn(self.TEST_URL, output) - self.assertIn(list(response.keys())[0], output) - self.assertIn(list(response.values())[0], output) - - self.assertNotIn(self.TEST_URL, self.logger.output) - self.assertNotIn(list(response.keys())[0], self.logger.output) - self.assertNotIn(list(response.values())[0], self.logger.output) - - -class ConfLoadingTests(utils.TestCase): - - GROUP = 'sessiongroup' - - def setUp(self): - super(ConfLoadingTests, self).setUp() - - self.conf_fixture = self.useFixture(config.Config()) - client_session.Session.register_conf_options(self.conf_fixture.conf, - self.GROUP) - - def config(self, **kwargs): - kwargs['group'] = self.GROUP - self.conf_fixture.config(**kwargs) - - def get_session(self, **kwargs): - with self.deprecations.expect_deprecations_here(): - return client_session.Session.load_from_conf_options( - self.conf_fixture.conf, - self.GROUP, - **kwargs) - - def test_insecure_timeout(self): - self.config(insecure=True, timeout=5) - s = self.get_session() - - self.assertFalse(s.verify) - self.assertEqual(5, s.timeout) - - def test_client_certs(self): - cert = '/path/to/certfile' - key = '/path/to/keyfile' - - self.config(certfile=cert, keyfile=key) - s = self.get_session() - - self.assertTrue(s.verify) - self.assertEqual((cert, key), s.cert) - - def test_cacert(self): - cafile = '/path/to/cacert' - - self.config(cafile=cafile) - s = self.get_session() - - self.assertEqual(cafile, s.verify) - - def test_deprecated(self): - def new_deprecated(): - return cfg.DeprecatedOpt(uuid.uuid4().hex, group=uuid.uuid4().hex) - - opt_names = ['cafile', 'certfile', 'keyfile', 'insecure', 'timeout'] - depr = dict([(n, [new_deprecated()]) for n in opt_names]) - opts = client_session.Session.get_conf_options(deprecated_opts=depr) - - self.assertThat(opt_names, matchers.HasLength(len(opts))) - for opt in opts: - self.assertIn(depr[opt.name][0], opt.deprecated_opts) - - -class CliLoadingTests(utils.TestCase): - - def setUp(self): - super(CliLoadingTests, self).setUp() - - self.parser = argparse.ArgumentParser() - client_session.Session.register_cli_options(self.parser) - - def get_session(self, val, **kwargs): - args = self.parser.parse_args(val.split()) - with self.deprecations.expect_deprecations_here(): - return client_session.Session.load_from_cli_options(args, **kwargs) - - def test_insecure_timeout(self): - s = self.get_session('--insecure --timeout 5.5') - - self.assertFalse(s.verify) - self.assertEqual(5.5, s.timeout) - - def test_client_certs(self): - cert = '/path/to/certfile' - key = '/path/to/keyfile' - - s = self.get_session('--os-cert %s --os-key %s' % (cert, key)) - - self.assertTrue(s.verify) - self.assertEqual((cert, key), s.cert) - - def test_cacert(self): - cacert = '/path/to/cacert' - - s = self.get_session('--os-cacert %s' % cacert) - - self.assertEqual(cacert, s.verify) diff --git a/keystoneclient/tests/unit/test_utils.py b/keystoneclient/tests/unit/test_utils.py deleted file mode 100644 index 01443314..00000000 --- a/keystoneclient/tests/unit/test_utils.py +++ /dev/null @@ -1,134 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1 import exceptions as ksa_exceptions -import six -import testresources -from testtools import matchers - - -from keystoneclient import exceptions as ksc_exceptions -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils as test_utils -from keystoneclient import utils - - -class FakeResource(object): - pass - - -class FakeManager(object): - - resource_class = FakeResource - - resources = { - '1234': {'name': 'entity_one'}, - '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0': {'name': 'entity_two'}, - '\xe3\x82\xbdtest': {'name': u'\u30bdtest'}, - '5678': {'name': '9876'} - } - - def get(self, resource_id): - try: - return self.resources[str(resource_id)] - except KeyError: - raise ksa_exceptions.NotFound(resource_id) - - def find(self, name=None): - if name == '9999': - # NOTE(morganfainberg): special case that raises NoUniqueMatch. - raise ksc_exceptions.NoUniqueMatch() - for resource_id, resource in self.resources.items(): - if resource['name'] == str(name): - return resource - raise ksa_exceptions.NotFound(name) - - -class FindResourceTestCase(test_utils.TestCase): - - def setUp(self): - super(FindResourceTestCase, self).setUp() - self.manager = FakeManager() - - def test_find_none(self): - self.assertRaises(ksc_exceptions.CommandError, - utils.find_resource, - self.manager, - 'asdf') - - def test_find_by_integer_id(self): - output = utils.find_resource(self.manager, 1234) - self.assertEqual(output, self.manager.resources['1234']) - - def test_find_by_str_id(self): - output = utils.find_resource(self.manager, '1234') - self.assertEqual(output, self.manager.resources['1234']) - - def test_find_by_uuid(self): - uuid = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0' - output = utils.find_resource(self.manager, uuid) - self.assertEqual(output, self.manager.resources[uuid]) - - def test_find_by_unicode(self): - name = '\xe3\x82\xbdtest' - output = utils.find_resource(self.manager, name) - self.assertEqual(output, self.manager.resources[name]) - - def test_find_by_str_name(self): - output = utils.find_resource(self.manager, 'entity_one') - self.assertEqual(output, self.manager.resources['1234']) - - def test_find_by_int_name(self): - output = utils.find_resource(self.manager, 9876) - self.assertEqual(output, self.manager.resources['5678']) - - def test_find_no_unique_match(self): - self.assertRaises(ksc_exceptions.CommandError, - utils.find_resource, - self.manager, - 9999) - - -class FakeObject(object): - def __init__(self, name): - self.name = name - - -class HashSignedTokenTestCase(test_utils.TestCase, - testresources.ResourcedTestCase): - """Unit tests for utils.hash_signed_token().""" - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_default_md5(self): - """The default hash method is md5.""" - token = self.examples.SIGNED_TOKEN_SCOPED - if six.PY3: - token = token.encode('utf-8') - token_id_default = utils.hash_signed_token(token) - token_id_md5 = utils.hash_signed_token(token, mode='md5') - self.assertThat(token_id_default, matchers.Equals(token_id_md5)) - # md5 hash is 32 chars. - self.assertThat(token_id_default, matchers.HasLength(32)) - - def test_sha256(self): - """Can also hash with sha256.""" - token = self.examples.SIGNED_TOKEN_SCOPED - if six.PY3: - token = token.encode('utf-8') - token_id = utils.hash_signed_token(token, mode='sha256') - # sha256 hash is 64 chars. - self.assertThat(token_id, matchers.HasLength(64)) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/utils.py b/keystoneclient/tests/unit/utils.py deleted file mode 100644 index 6921b4b0..00000000 --- a/keystoneclient/tests/unit/utils.py +++ /dev/null @@ -1,184 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import sys -import uuid - -import fixtures -from oslo_serialization import jsonutils -import requests -import requests_mock -from requests_mock.contrib import fixture -from six.moves.urllib import parse as urlparse -import testscenarios -import testtools - -from keystoneclient.tests.unit import client_fixtures - - -class TestCase(testtools.TestCase): - - TEST_DOMAIN_ID = uuid.uuid4().hex - TEST_DOMAIN_NAME = uuid.uuid4().hex - TEST_GROUP_ID = uuid.uuid4().hex - TEST_ROLE_ID = uuid.uuid4().hex - TEST_TENANT_ID = uuid.uuid4().hex - TEST_TENANT_NAME = uuid.uuid4().hex - TEST_TOKEN = uuid.uuid4().hex - TEST_TRUST_ID = uuid.uuid4().hex - TEST_USER = uuid.uuid4().hex - TEST_USER_ID = uuid.uuid4().hex - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - - def setUp(self): - super(TestCase, self).setUp() - self.deprecations = self.useFixture(client_fixtures.Deprecations()) - - self.logger = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG)) - self.requests_mock = self.useFixture(fixture.Fixture()) - - def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs): - if not base_url: - base_url = self.TEST_URL - - if json: - kwargs['text'] = jsonutils.dumps(json) - headers = kwargs.setdefault('headers', {}) - headers['Content-Type'] = 'application/json' - - if parts: - url = '/'.join([p.strip('/') for p in [base_url] + parts]) - else: - url = base_url - - url = url.replace("/?", "?") - self.requests_mock.register_uri(method, url, **kwargs) - - def assertRequestBodyIs(self, body=None, json=None): - last_request_body = self.requests_mock.last_request.body - if json: - val = jsonutils.loads(last_request_body) - self.assertEqual(json, val) - elif body: - self.assertEqual(body, last_request_body) - - def assertQueryStringIs(self, qs=''): - r"""Verify the QueryString matches what is expected. - - The qs parameter should be of the format \'foo=bar&abc=xyz\' - """ - expected = urlparse.parse_qs(qs, keep_blank_values=True) - parts = urlparse.urlparse(self.requests_mock.last_request.url) - querystring = urlparse.parse_qs(parts.query, keep_blank_values=True) - self.assertEqual(expected, querystring) - - def assertQueryStringContains(self, **kwargs): - """Verify the query string contains the expected parameters. - - This method is used to verify that the query string for the most recent - request made contains all the parameters provided as ``kwargs``, and - that the value of each parameter contains the value for the kwarg. If - the value for the kwarg is an empty string (''), then all that's - verified is that the parameter is present. - - """ - parts = urlparse.urlparse(self.requests_mock.last_request.url) - qs = urlparse.parse_qs(parts.query, keep_blank_values=True) - - for k, v in kwargs.items(): - self.assertIn(k, qs) - self.assertIn(v, qs[k]) - - def assertRequestHeaderEqual(self, name, val): - """Verify that the last request made contains a header and its value. - - The request must have already been made. - """ - headers = self.requests_mock.last_request.headers - self.assertEqual(headers.get(name), val) - - -def test_response(**kwargs): - r = requests.Request(method='GET', url='http://localhost:5000').prepare() - return requests_mock.create_response(r, **kwargs) - - -class DisableModuleFixture(fixtures.Fixture): - """A fixture to provide support for unloading/disabling modules.""" - - def __init__(self, module, *args, **kw): - super(DisableModuleFixture, self).__init__(*args, **kw) - self.module = module - self._finders = [] - self._cleared_modules = {} - - def tearDown(self): - super(DisableModuleFixture, self).tearDown() - for finder in self._finders: - sys.meta_path.remove(finder) - sys.modules.update(self._cleared_modules) - - def clear_module(self): - cleared_modules = {} - for fullname in list(sys.modules): - if (fullname == self.module or - fullname.startswith(self.module + '.')): - cleared_modules[fullname] = sys.modules.pop(fullname) - return cleared_modules - - def setUp(self): - """Ensure ImportError for the specified module.""" - super(DisableModuleFixture, self).setUp() - - # Clear 'module' references in sys.modules - self._cleared_modules.update(self.clear_module()) - - finder = NoModuleFinder(self.module) - self._finders.append(finder) - sys.meta_path.insert(0, finder) - - -class ClientTestCaseMixin(testscenarios.WithScenarios): - - client_fixture_class = None - data_fixture_class = None - - def setUp(self): - super(ClientTestCaseMixin, self).setUp() - - self.data_fixture = None - self.client_fixture = None - self.client = None - - if self.client_fixture_class: - fix = self.client_fixture_class(self.requests_mock, - self.deprecations) - self.client_fixture = self.useFixture(fix) - self.client = self.client_fixture.client - self.TEST_USER_ID = self.client_fixture.user_id - - if self.data_fixture_class: - fix = self.data_fixture_class(self.requests_mock) - self.data_fixture = self.useFixture(fix) - - -class NoModuleFinder(object): - """Disallow further imports of 'module'.""" - - def __init__(self, module): - self.module = module - - def find_module(self, fullname, path): - if fullname == self.module or fullname.startswith(self.module + '.'): - raise ImportError diff --git a/keystoneclient/tests/unit/v2_0/__init__.py b/keystoneclient/tests/unit/v2_0/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/v2_0/client_fixtures.py b/keystoneclient/tests/unit/v2_0/client_fixtures.py deleted file mode 100644 index 019b9445..00000000 --- a/keystoneclient/tests/unit/v2_0/client_fixtures.py +++ /dev/null @@ -1,127 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from __future__ import unicode_literals -import uuid - -from keystoneauth1 import fixture - - -def unscoped_token(): - return fixture.V2Token(token_id='3e2813b7ba0b4006840c3825860b86ed', - expires='2012-10-03T16:58:01Z', - user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser') - - -def project_scoped_token(): - _TENANT_ID = '225da22d3ce34b15877ea70b2a575f58' - - f = fixture.V2Token(token_id='04c7d5ffaeef485f9dc69c06db285bdb', - expires='2012-10-03T16:53:36Z', - tenant_id='225da22d3ce34b15877ea70b2a575f58', - tenant_name='exampleproject', - user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser', - audit_chain_id=uuid.uuid4().hex) - - f.add_role(id='member_id', name='Member') - - s = f.add_service('volume', 'Volume Service') - s.add_endpoint(public='http://public.com:8776/v1/%s' % _TENANT_ID, - admin='http://admin:8776/v1/%s' % _TENANT_ID, - internal='http://internal:8776/v1/%s' % _TENANT_ID, - region='RegionOne') - - s = f.add_service('image', 'Image Service') - s.add_endpoint(public='http://public.com:9292/v1', - admin='http://admin:9292/v1', - internal='http://internal:9292/v1', - region='RegionOne') - - s = f.add_service('compute', 'Compute Service') - s.add_endpoint(public='http://public.com:8774/v2/%s' % _TENANT_ID, - admin='http://admin:8774/v2/%s' % _TENANT_ID, - internal='http://internal:8774/v2/%s' % _TENANT_ID, - region='RegionOne') - - s = f.add_service('ec2', 'EC2 Service') - s.add_endpoint(public='http://public.com:8773/services/Cloud', - admin='http://admin:8773/services/Admin', - internal='http://internal:8773/services/Cloud', - region='RegionOne') - - s = f.add_service('identity', 'Identity Service') - s.add_endpoint(public='http://public.com:5000/v2.0', - admin='http://admin:35357/v2.0', - internal='http://internal:5000/v2.0', - region='RegionOne') - - return f - - -def auth_response_body(): - f = fixture.V2Token(token_id='ab48a9efdfedb23ty3494', - expires='2010-11-01T03:32:15-05:00', - tenant_id='345', - tenant_name='My Project', - user_id='123', - user_name='jqsmith', - audit_chain_id=uuid.uuid4().hex) - - f.add_role(id='234', name='compute:admin') - role = f.add_role(id='235', name='object-store:admin') - role['tenantId'] = '1' - - s = f.add_service('compute', 'Cloud Servers') - endpoint = s.add_endpoint(public='https://compute.north.host/v1/1234', - internal='https://compute.north.host/v1/1234', - region='North') - endpoint['tenantId'] = '1' - endpoint['versionId'] = '1.0' - endpoint['versionInfo'] = 'https://compute.north.host/v1.0/' - endpoint['versionList'] = 'https://compute.north.host/' - - endpoint = s.add_endpoint(public='https://compute.north.host/v1.1/3456', - internal='https://compute.north.host/v1.1/3456', - region='North') - endpoint['tenantId'] = '2' - endpoint['versionId'] = '1.1' - endpoint['versionInfo'] = 'https://compute.north.host/v1.1/' - endpoint['versionList'] = 'https://compute.north.host/' - - s = f.add_service('object-store', 'Cloud Files') - endpoint = s.add_endpoint(public='https://swift.north.host/v1/blah', - internal='https://swift.north.host/v1/blah', - region='South') - endpoint['tenantId'] = '11' - endpoint['versionId'] = '1.0' - endpoint['versionInfo'] = 'uri' - endpoint['versionList'] = 'uri' - - endpoint = s.add_endpoint(public='https://swift.north.host/v1.1/blah', - internal='https://compute.north.host/v1.1/blah', - region='South') - endpoint['tenantId'] = '2' - endpoint['versionId'] = '1.1' - endpoint['versionInfo'] = 'https://swift.north.host/v1.1/' - endpoint['versionList'] = 'https://swift.north.host/' - - s = f.add_service('image', 'Image Servers') - s.add_endpoint(public='https://image.north.host/v1/', - internal='https://image-internal.north.host/v1/', - region='North') - s.add_endpoint(public='https://image.south.host/v1/', - internal='https://image-internal.south.host/v1/', - region='South') - - return f diff --git a/keystoneclient/tests/unit/v2_0/test_access.py b/keystoneclient/tests/unit/v2_0/test_access.py deleted file mode 100644 index 95556aff..00000000 --- a/keystoneclient/tests/unit/v2_0/test_access.py +++ /dev/null @@ -1,217 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime -import uuid - -from keystoneauth1 import fixture -from oslo_utils import timeutils -import testresources - -from keystoneclient import access -from keystoneclient.tests.unit import client_fixtures as token_data -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils - - -class AccessInfoTest(utils.TestCase, testresources.ResourcedTestCase): - - resources = [('examples', token_data.EXAMPLES_RESOURCE)] - - def test_building_unscoped_accessinfo(self): - token = client_fixtures.unscoped_token() - auth_ref = access.AccessInfo.factory(body=token) - - self.assertTrue(auth_ref) - self.assertIn('token', auth_ref) - - self.assertEqual(auth_ref.auth_token, - '3e2813b7ba0b4006840c3825860b86ed') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') - - self.assertEqual(auth_ref.role_ids, []) - self.assertEqual(auth_ref.role_names, []) - - self.assertIsNone(auth_ref.tenant_name) - self.assertIsNone(auth_ref.tenant_id) - - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.auth_url) - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.management_url) - - with self.deprecations.expect_deprecations_here(): - self.assertFalse(auth_ref.scoped) - self.assertFalse(auth_ref.domain_scoped) - self.assertFalse(auth_ref.project_scoped) - self.assertFalse(auth_ref.trust_scoped) - - self.assertIsNone(auth_ref.project_domain_id) - self.assertIsNone(auth_ref.project_domain_name) - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - - self.assertEqual(auth_ref.expires, token.expires) - self.assertEqual(auth_ref.issued, token.issued) - - self.assertEqual(token.audit_id, auth_ref.audit_id) - self.assertIsNone(auth_ref.audit_chain_id) - self.assertIsNone(token.audit_chain_id) - - def test_will_expire_soon(self): - token = client_fixtures.unscoped_token() - expires = timeutils.utcnow() + datetime.timedelta(minutes=5) - token.expires = expires - auth_ref = access.AccessInfo.factory(body=token) - self.assertFalse(auth_ref.will_expire_soon(stale_duration=120)) - self.assertTrue(auth_ref.will_expire_soon(stale_duration=300)) - self.assertFalse(auth_ref.will_expire_soon()) - - def test_building_scoped_accessinfo(self): - token = client_fixtures.project_scoped_token() - auth_ref = access.AccessInfo.factory(body=token) - - self.assertTrue(auth_ref) - self.assertIn('token', auth_ref) - self.assertIn('serviceCatalog', auth_ref) - self.assertTrue(auth_ref['serviceCatalog']) - - self.assertEqual(auth_ref.auth_token, - '04c7d5ffaeef485f9dc69c06db285bdb') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') - - self.assertEqual(auth_ref.role_ids, ['member_id']) - self.assertEqual(auth_ref.role_names, ['Member']) - - self.assertEqual(auth_ref.tenant_name, 'exampleproject') - self.assertEqual(auth_ref.tenant_id, - '225da22d3ce34b15877ea70b2a575f58') - - self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) - self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.auth_url, - ('http://public.com:5000/v2.0',)) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.management_url, - ('http://admin:35357/v2.0',)) - - self.assertEqual(auth_ref.project_domain_id, 'default') - self.assertEqual(auth_ref.project_domain_name, 'Default') - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - - with self.deprecations.expect_deprecations_here(): - self.assertTrue(auth_ref.scoped) - self.assertTrue(auth_ref.project_scoped) - self.assertFalse(auth_ref.domain_scoped) - - self.assertEqual(token.audit_id, auth_ref.audit_id) - self.assertEqual(token.audit_chain_id, auth_ref.audit_chain_id) - - def test_diablo_token(self): - diablo_token = self.examples.TOKEN_RESPONSES[ - self.examples.VALID_DIABLO_TOKEN] - auth_ref = access.AccessInfo.factory(body=diablo_token) - - self.assertTrue(auth_ref) - self.assertEqual(auth_ref.username, 'user_name1') - self.assertEqual(auth_ref.project_id, 'tenant_id1') - self.assertEqual(auth_ref.project_name, 'tenant_id1') - self.assertEqual(auth_ref.project_domain_id, 'default') - self.assertEqual(auth_ref.project_domain_name, 'Default') - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - self.assertEqual(auth_ref.role_names, ['role1', 'role2']) - with self.deprecations.expect_deprecations_here(): - self.assertFalse(auth_ref.scoped) - - def test_grizzly_token(self): - grizzly_token = self.examples.TOKEN_RESPONSES[ - self.examples.SIGNED_TOKEN_SCOPED_KEY] - auth_ref = access.AccessInfo.factory(body=grizzly_token) - - self.assertEqual(auth_ref.project_id, 'tenant_id1') - self.assertEqual(auth_ref.project_name, 'tenant_name1') - self.assertEqual(auth_ref.project_domain_id, 'default') - self.assertEqual(auth_ref.project_domain_name, 'Default') - self.assertEqual(auth_ref.user_domain_id, 'default') - self.assertEqual(auth_ref.user_domain_name, 'Default') - self.assertEqual(auth_ref.role_names, ['role1', 'role2']) - - def test_v2_roles(self): - role_id = 'a' - role_name = 'b' - - token = fixture.V2Token() - token.set_scope() - token.add_role(id=role_id, name=role_name) - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual([role_id], auth_ref.role_ids) - self.assertEqual([role_id], auth_ref['metadata']['roles']) - self.assertEqual([role_name], auth_ref.role_names) - self.assertEqual([{'name': role_name}], auth_ref['user']['roles']) - - def test_trusts(self): - user_id = uuid.uuid4().hex - trust_id = uuid.uuid4().hex - - token = fixture.V2Token(user_id=user_id, trust_id=trust_id) - token.set_scope() - token.add_role() - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual(trust_id, auth_ref.trust_id) - self.assertEqual(user_id, auth_ref.trustee_user_id) - - self.assertEqual(trust_id, token['access']['trust']['id']) - - def test_override_auth_token(self): - token = fixture.V2Token() - token.set_scope() - token.add_role() - - new_auth_token = uuid.uuid4().hex - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual(token.token_id, auth_ref.auth_token) - - auth_ref.auth_token = new_auth_token - self.assertEqual(new_auth_token, auth_ref.auth_token) - - del auth_ref.auth_token - self.assertEqual(token.token_id, auth_ref.auth_token) - - def test_override_auth_token_in_factory(self): - token = fixture.V2Token() - token.set_scope() - token.add_role() - - new_auth_token = uuid.uuid4().hex - - auth_ref = access.AccessInfo.factory(body=token, - auth_token=new_auth_token) - - self.assertEqual(new_auth_token, auth_ref.auth_token) - del auth_ref.auth_token - self.assertEqual(token.token_id, auth_ref.auth_token) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v2_0/test_auth.py b/keystoneclient/tests/unit/v2_0/test_auth.py deleted file mode 100644 index 64f2ea03..00000000 --- a/keystoneclient/tests/unit/v2_0/test_auth.py +++ /dev/null @@ -1,268 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import datetime - -from oslo_serialization import jsonutils -from oslo_utils import timeutils -from testtools import testcase - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client - - -class AuthenticateAgainstKeystoneTests(utils.TestCase): - def setUp(self): - super(AuthenticateAgainstKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10.000123Z", - "id": self.TEST_TOKEN, - "tenant": { - "id": self.TEST_TENANT_ID - }, - }, - "user": { - "id": self.TEST_USER - }, - "serviceCatalog": self.TEST_SERVICE_CATALOG, - }, - } - self.TEST_REQUEST_BODY = { - "auth": { - "passwordCredentials": { - "username": self.TEST_USER, - "password": self.TEST_TOKEN, - }, - "tenantId": self.TEST_TENANT_ID, - }, - } - - def test_authenticate_success_expired(self): - resp_a = copy.deepcopy(self.TEST_RESPONSE_DICT) - resp_b = copy.deepcopy(self.TEST_RESPONSE_DICT) - headers = {'Content-Type': 'application/json'} - - # Build an expired token - resp_a['access']['token']['expires'] = ( - (timeutils.utcnow() - datetime.timedelta(1)).isoformat()) - - # Build a new response - TEST_TOKEN = "abcdef" - resp_b['access']['token']['expires'] = '2020-01-01T00:00:10.000123Z' - resp_b['access']['token']['id'] = TEST_TOKEN - - # return expired first, and then the new response - self.stub_auth(response_list=[{'json': resp_a, 'headers': headers}, - {'json': resp_b, 'headers': headers}]) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_TOKEN) - - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(cs.auth_token, TEST_TOKEN) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_failure(self): - _auth = 'auth' - _cred = 'passwordCredentials' - _pass = 'password' - self.TEST_REQUEST_BODY[_auth][_cred][_pass] = 'bad_key' - error = {"unauthorized": {"message": "Unauthorized", - "code": "401"}} - - self.stub_auth(status_code=401, json=error) - - with testcase.ExpectedException(exceptions.Unauthorized): - with self.deprecations.expect_deprecations_here(): - client.Client(username=self.TEST_USER, - password="bad_key", - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_redirect(self): - self.stub_auth(status_code=305, text='Use Proxy', - headers={'Location': self.TEST_ADMIN_URL + "/tokens"}) - - self.stub_auth(base_url=self.TEST_ADMIN_URL, - json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_password_unscoped(self): - del self.TEST_RESPONSE_DICT['access']['serviceCatalog'] - del self.TEST_REQUEST_BODY['auth']['tenantId'] - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertNotIn('serviceCatalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_url_token_authentication(self): - fake_token = 'fake_token' - fake_url = '/fake-url' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - with self.deprecations.expect_deprecations_here(): - cl = client.Client(auth_url=self.TEST_URL, - token=fake_token) - json_body = jsonutils.loads(self.requests_mock.last_request.body) - self.assertEqual(json_body['auth']['token']['id'], fake_token) - - with self.deprecations.expect_deprecations_here(): - resp, body = cl.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - def test_authenticate_success_token_scoped(self): - del self.TEST_REQUEST_BODY['auth']['passwordCredentials'] - self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] - ['endpoints'][0]["adminURL"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_scoped_trust(self): - del self.TEST_REQUEST_BODY['auth']['passwordCredentials'] - self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} - self.TEST_REQUEST_BODY['auth']['trust_id'] = self.TEST_TRUST_ID - response = self.TEST_RESPONSE_DICT.copy() - response['access']['trust'] = {"trustee_user_id": self.TEST_USER, - "id": self.TEST_TRUST_ID} - self.stub_auth(json=response) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - trust_id=self.TEST_TRUST_ID, - auth_url=self.TEST_URL) - self.assertTrue(cs.auth_ref.trust_scoped) - self.assertEqual(cs.auth_ref.trust_id, self.TEST_TRUST_ID) - self.assertEqual(cs.auth_ref.trustee_user_id, self.TEST_USER) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_unscoped(self): - del self.TEST_REQUEST_BODY['auth']['passwordCredentials'] - del self.TEST_REQUEST_BODY['auth']['tenantId'] - del self.TEST_RESPONSE_DICT['access']['serviceCatalog'] - self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_DICT["access"]["token"]["id"]) - self.assertNotIn('serviceCatalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_allow_override_of_auth_token(self): - fake_url = '/fake-url' - fake_token = 'fake_token' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - - self.assertEqual(cl.auth_token, self.TEST_TOKEN) - - # the token returned from the authentication will be used - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - # then override that token and the new token shall be used - cl.auth_token = fake_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(fake_token, token) - - # if we clear that overridden token then we fall back to the original - del cl.auth_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) diff --git a/keystoneclient/tests/unit/v2_0/test_certificates.py b/keystoneclient/tests/unit/v2_0/test_certificates.py deleted file mode 100644 index 4f689d9a..00000000 --- a/keystoneclient/tests/unit/v2_0/test_certificates.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 IBM Corp. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testresources - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils - - -class CertificateTests(utils.ClientTestCase, testresources.ResourcedTestCase): - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_get_ca_certificate(self): - self.stub_url('GET', ['certificates', 'ca'], - headers={'Content-Type': 'text/html; charset=UTF-8'}, - text=self.examples.SIGNING_CA) - res = self.client.certificates.get_ca_certificate() - self.assertEqual(self.examples.SIGNING_CA, res) - - def test_get_signing_certificate(self): - self.stub_url('GET', ['certificates', 'signing'], - headers={'Content-Type': 'text/html; charset=UTF-8'}, - text=self.examples.SIGNING_CERT) - res = self.client.certificates.get_signing_certificate() - self.assertEqual(self.examples.SIGNING_CERT, res) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v2_0/test_client.py b/keystoneclient/tests/unit/v2_0/test_client.py deleted file mode 100644 index cddac4d2..00000000 --- a/keystoneclient/tests/unit/v2_0/test_client.py +++ /dev/null @@ -1,220 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json -import uuid - -from keystoneauth1 import fixture - -from keystoneauth1 import session as auth_session -from keystoneclient.auth import token_endpoint -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client - - -class KeystoneClientTest(utils.TestCase): - - def test_unscoped_init(self): - token = client_fixtures.unscoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username='exampleuser', - password='password', - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertFalse(c.auth_ref.scoped) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertIsNone(c.auth_ref.trust_id) - self.assertFalse(c.auth_ref.trust_scoped) - self.assertIsNone(c.get_project_id(session=None)) - self.assertEqual(token.user_id, c.get_user_id(session=None)) - - def test_scoped_init(self): - token = client_fixtures.project_scoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertTrue(c.auth_ref.scoped) - self.assertTrue(c.auth_ref.project_scoped) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertIsNone(c.auth_ref.trust_id) - self.assertFalse(c.auth_ref.trust_scoped) - - self.assertEqual(token.tenant_id, c.get_project_id(session=None)) - self.assertEqual(token.user_id, c.get_user_id(session=None)) - - def test_auth_ref_load(self): - self.stub_auth(json=client_fixtures.project_scoped_token()) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - cache = json.dumps(cl.auth_ref) - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache)) - self.assertIsNotNone(new_client.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertTrue(new_client.auth_ref.scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertIsNone(new_client.auth_ref.trust_id) - self.assertFalse(new_client.auth_ref.trust_scoped) - self.assertEqual(new_client.username, 'exampleuser') - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v2.0') - - def test_auth_ref_load_with_overridden_arguments(self): - self.stub_auth(json=client_fixtures.project_scoped_token()) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - cache = json.dumps(cl.auth_ref) - new_auth_url = "http://new-public:5000/v2.0" - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache), - auth_url=new_auth_url) - self.assertIsNotNone(new_client.auth_ref) - with self.deprecations.expect_deprecations_here(): - self.assertTrue(new_client.auth_ref.scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertIsNone(new_client.auth_ref.trust_id) - self.assertFalse(new_client.auth_ref.trust_scoped) - self.assertEqual(new_client.auth_url, new_auth_url) - self.assertEqual(new_client.username, 'exampleuser') - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v2.0') - - def test_init_err_no_auth_url(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - username='exampleuser', - password='password') - - def test_management_url_is_updated(self): - first = fixture.V2Token() - first.set_scope() - admin_url = 'http://admin:35357/v2.0' - second_url = 'http://secondurl:35357/v2.0' - - s = first.add_service('identity') - s.add_endpoint(public='http://public.com:5000/v2.0', - admin=admin_url) - - second = fixture.V2Token() - second.set_scope() - s = second.add_service('identity') - s.add_endpoint(public='http://secondurl:5000/v2.0', - admin=second_url) - - self.stub_auth(response_list=[{'json': first}, {'json': second}]) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - self.assertEqual(cl.management_url, admin_url) - - with self.deprecations.expect_deprecations_here(): - cl.authenticate() - self.assertEqual(cl.management_url, second_url) - - def test_client_with_region_name_passes_to_service_catalog(self): - # NOTE(jamielennox): this is deprecated behaviour that should be - # removed ASAP, however must remain compatible. - self.stub_auth(json=client_fixtures.auth_response_body()) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='North') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'https://image.north.host/v1/') - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='South') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'https://image.south.host/v1/') - - def test_client_without_auth_params(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - project_name='exampleproject', - auth_url=self.TEST_URL) - - def test_client_params(self): - with self.deprecations.expect_deprecations_here(): - sess = session.Session() - auth = token_endpoint.Token('a', 'b') - - opts = {'auth': auth, - 'connect_retries': 50, - 'endpoint_override': uuid.uuid4().hex, - 'interface': uuid.uuid4().hex, - 'region_name': uuid.uuid4().hex, - 'service_name': uuid.uuid4().hex, - 'user_agent': uuid.uuid4().hex, - } - - cl = client.Client(session=sess, **opts) - - for k, v in opts.items(): - self.assertEqual(v, getattr(cl._adapter, k)) - - self.assertEqual('identity', cl._adapter.service_type) - self.assertEqual((2, 0), cl._adapter.version) - - def test_empty_service_catalog_param(self): - # Client().service_catalog should return None if the client is not - # authenticated - sess = auth_session.Session() - cl = client.Client(session=sess) - self.assertIsNone(cl.service_catalog) diff --git a/keystoneclient/tests/unit/v2_0/test_discovery.py b/keystoneclient/tests/unit/v2_0/test_discovery.py deleted file mode 100644 index a3700e0e..00000000 --- a/keystoneclient/tests/unit/v2_0/test_discovery.py +++ /dev/null @@ -1,84 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from keystoneclient.generic import client -from keystoneclient.tests.unit.v2_0 import utils - - -class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): - def setUp(self): - super(DiscoverKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "versions": { - "values": [{ - "id": "v2.0", - "status": "beta", - "updated": "2011-11-19T00:00:00Z", - "links": [ - {"rel": "self", - "href": "http://127.0.0.1:5000/v2.0/", }, - {"rel": "describedby", - "type": "text/html", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/content/", }, - {"rel": "describedby", - "type": "application/pdf", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/" - "identity-dev-guide-2.0.pdf", }, - {"rel": "describedby", - "type": "application/vnd.sun.wadl+xml", - "href": "http://127.0.0.1:5000/v2.0/identity.wadl", } - ], - "media-types": [{ - "base": "application/xml", - "type": "application/vnd.openstack.identity-v2.0+xml", - }, { - "base": "application/json", - "type": "application/vnd.openstack.identity-v2.0+json", - }], - }], - }, - } - - def test_get_versions(self): - self.stub_url('GET', base_url=self.TEST_ROOT_URL, - json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client() - versions = cs.discover(self.TEST_ROOT_URL) - self.assertIsInstance(versions, dict) - self.assertIn('message', versions) - self.assertIn('v2.0', versions) - self.assertEqual( - versions['v2.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][0]['links'][0] - ['href']) - - def test_get_version_local(self): - self.stub_url('GET', base_url="http://localhost:35357/", - json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client() - versions = cs.discover() - self.assertIsInstance(versions, dict) - self.assertIn('message', versions) - self.assertIn('v2.0', versions) - self.assertEqual( - versions['v2.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][0]['links'][0] - ['href']) diff --git a/keystoneclient/tests/unit/v2_0/test_ec2.py b/keystoneclient/tests/unit/v2_0/test_ec2.py deleted file mode 100644 index 3df053de..00000000 --- a/keystoneclient/tests/unit/v2_0/test_ec2.py +++ /dev/null @@ -1,107 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import ec2 - - -class EC2Tests(utils.ClientTestCase): - - def test_create(self): - user_id = 'usr' - tenant_id = 'tnt' - req_body = { - "tenant_id": tenant_id, - } - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('POST', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - cred = self.client.ec2.create(user_id, tenant_id) - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - self.assertRequestBodyIs(json=req_body) - - def test_get(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2', 'access'], json=resp_body) - - cred = self.client.ec2.get(user_id, 'access') - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_list(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credentials": { - "values": [ - { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - }, - { - "access": "another", - "secret": "key", - "tenant_id": tenant_id, - "created": "12/12/31", - "enabled": True, - } - ] - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - creds = self.client.ec2.list(user_id) - self.assertEqual(len(creds), 2) - cred = creds[0] - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_delete(self): - user_id = 'usr' - access = 'access' - self.stub_url('DELETE', ['users', user_id, 'credentials', - 'OS-EC2', access], status_code=204) - self.client.ec2.delete(user_id, access) diff --git a/keystoneclient/tests/unit/v2_0/test_endpoints.py b/keystoneclient/tests/unit/v2_0/test_endpoints.py deleted file mode 100644 index 7b15cccc..00000000 --- a/keystoneclient/tests/unit/v2_0/test_endpoints.py +++ /dev/null @@ -1,147 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import endpoints - - -class EndpointTests(utils.ClientTestCase): - def setUp(self): - super(EndpointTests, self).setUp() - self.TEST_ENDPOINTS = { - 'endpoints': [ - { - 'adminurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'id': '8f9531231e044e218824b0e58688d262', - 'internalurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'publicurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'region': 'RegionOne', - }, - { - 'adminurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'id': '8f9531231e044e218824b0e58688d263', - 'internalurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'publicurl': 'http://host-1:8774/v1.1/$(tenant_id)s', - 'region': 'RegionOne', - } - ] - } - - def test_create_with_optional_params(self): - req_body = { - "endpoint": { - "region": "RegionOne", - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "internalurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "service_id": uuid.uuid4().hex, - } - } - - resp_body = { - "endpoint": { - "adminurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "region": "RegionOne", - "id": uuid.uuid4().hex, - "internalurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - } - } - - self.stub_url('POST', ['endpoints'], json=resp_body) - - endpoint = self.client.endpoints.create( - region=req_body['endpoint']['region'], - publicurl=req_body['endpoint']['publicurl'], - adminurl=req_body['endpoint']['adminurl'], - internalurl=req_body['endpoint']['internalurl'], - service_id=req_body['endpoint']['service_id'] - ) - self.assertIsInstance(endpoint, endpoints.Endpoint) - self.assertRequestBodyIs(json=req_body) - - def test_create_with_optional_params_as_none(self): - req_body_without_defaults = { - "endpoint": { - "region": "RegionOne", - "service_id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - resp_body = { - "endpoint": { - "region": "RegionOne", - "id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - self.stub_url('POST', ['endpoints'], json=resp_body) - - endpoint_without_defaults = self.client.endpoints.create( - region=req_body_without_defaults['endpoint']['region'], - publicurl=req_body_without_defaults['endpoint']['publicurl'], - service_id=req_body_without_defaults['endpoint']['service_id'], - adminurl=None, - internalurl=None - ) - self.assertIsInstance(endpoint_without_defaults, endpoints.Endpoint) - self.assertRequestBodyIs(json=req_body_without_defaults) - - def test_create_without_optional_params(self): - req_body_without_defaults = { - "endpoint": { - "region": "RegionOne", - "service_id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - resp_body = { - "endpoint": { - "region": "RegionOne", - "id": uuid.uuid4().hex, - "publicurl": "http://host-3:8774/v1.1/$(tenant_id)s", - "adminurl": None, - "internalurl": None, - } - } - - self.stub_url('POST', ['endpoints'], json=resp_body) - - endpoint_without_defaults = self.client.endpoints.create( - region=req_body_without_defaults['endpoint']['region'], - publicurl=req_body_without_defaults['endpoint']['publicurl'], - service_id=req_body_without_defaults['endpoint']['service_id'] - ) - self.assertIsInstance(endpoint_without_defaults, endpoints.Endpoint) - self.assertRequestBodyIs(json=req_body_without_defaults) - - def test_delete(self): - self.stub_url('DELETE', ['endpoints', '8f953'], status_code=204) - self.client.endpoints.delete('8f953') - - def test_list(self): - self.stub_url('GET', ['endpoints'], json=self.TEST_ENDPOINTS) - - endpoint_list = self.client.endpoints.list() - [self.assertIsInstance(r, endpoints.Endpoint) - for r in endpoint_list] diff --git a/keystoneclient/tests/unit/v2_0/test_extensions.py b/keystoneclient/tests/unit/v2_0/test_extensions.py deleted file mode 100644 index 3927bc07..00000000 --- a/keystoneclient/tests/unit/v2_0/test_extensions.py +++ /dev/null @@ -1,63 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import extensions - - -class ExtensionTests(utils.ClientTestCase): - def setUp(self): - super(ExtensionTests, self).setUp() - self.TEST_EXTENSIONS = { - 'extensions': { - "values": [ - { - 'name': 'OpenStack Keystone User CRUD', - 'namespace': 'https://docs.openstack.org/' - 'identity/api/ext/OS-KSCRUD/v1.0', - 'updated': '2013-07-07T12:00:0-00:00', - 'alias': 'OS-KSCRUD', - 'description': - 'OpenStack extensions to Keystone v2.0 API' - ' enabling User Operations.', - 'links': - '[{"href":' - '"https://github.com/openstack/identity-api", "type":' - ' "text/html", "rel": "describedby"}]', - }, - { - 'name': 'OpenStack EC2 API', - 'namespace': 'https://docs.openstack.org/' - 'identity/api/ext/OS-EC2/v1.0', - 'updated': '2013-09-07T12:00:0-00:00', - 'alias': 'OS-EC2', - 'description': 'OpenStack EC2 Credentials backend.', - 'links': '[{"href":' - '"https://github.com/openstack/identity-api", "type":' - ' "text/html", "rel": "describedby"}]', - } - ] - } - } - - def test_list(self): - self.stub_url('GET', ['extensions'], json=self.TEST_EXTENSIONS) - extensions_list = self.client.extensions.list() - self.assertEqual(2, len(extensions_list)) - for extension in extensions_list: - self.assertIsInstance(extension, extensions.Extension) - self.assertIsNotNone(extension.alias) - self.assertIsNotNone(extension.description) - self.assertIsNotNone(extension.links) - self.assertIsNotNone(extension.name) - self.assertIsNotNone(extension.namespace) - self.assertIsNotNone(extension.updated) diff --git a/keystoneclient/tests/unit/v2_0/test_roles.py b/keystoneclient/tests/unit/v2_0/test_roles.py deleted file mode 100644 index fab21383..00000000 --- a/keystoneclient/tests/unit/v2_0/test_roles.py +++ /dev/null @@ -1,121 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import roles - - -class RoleTests(utils.ClientTestCase): - def setUp(self): - super(RoleTests, self).setUp() - - self.ADMIN_ROLE_ID = uuid.uuid4().hex - self.MEMBER_ROLE_ID = uuid.uuid4().hex - - self.TEST_ROLES = { - "roles": { - "values": [ - { - "name": "admin", - "id": self.ADMIN_ROLE_ID, - }, - { - "name": "member", - "id": self.MEMBER_ROLE_ID, - } - ], - }, - } - - def test_create(self): - req_body = { - "role": { - "name": "sysadmin", - } - } - role_id = uuid.uuid4().hex - resp_body = { - "role": { - "name": "sysadmin", - "id": role_id, - } - } - self.stub_url('POST', ['OS-KSADM', 'roles'], json=resp_body) - - role = self.client.roles.create(req_body['role']['name']) - self.assertRequestBodyIs(json=req_body) - self.assertIsInstance(role, roles.Role) - self.assertEqual(role.id, role_id) - self.assertEqual(role.name, req_body['role']['name']) - - def test_delete(self): - self.stub_url('DELETE', - ['OS-KSADM', 'roles', self.ADMIN_ROLE_ID], - status_code=204) - self.client.roles.delete(self.ADMIN_ROLE_ID) - - def test_get(self): - self.stub_url('GET', ['OS-KSADM', 'roles', self.ADMIN_ROLE_ID], - json={'role': self.TEST_ROLES['roles']['values'][0]}) - - role = self.client.roles.get(self.ADMIN_ROLE_ID) - self.assertIsInstance(role, roles.Role) - self.assertEqual(role.id, self.ADMIN_ROLE_ID) - self.assertEqual(role.name, 'admin') - - def test_list(self): - self.stub_url('GET', ['OS-KSADM', 'roles'], - json=self.TEST_ROLES) - - role_list = self.client.roles.list() - [self.assertIsInstance(r, roles.Role) for r in role_list] - - def test_roles_for_user(self): - self.stub_url('GET', ['users', 'foo', 'roles'], - json=self.TEST_ROLES) - - role_list = self.client.roles.roles_for_user('foo') - [self.assertIsInstance(r, roles.Role) for r in role_list] - - def test_roles_for_user_tenant(self): - self.stub_url('GET', ['tenants', 'barrr', 'users', 'foo', - 'roles'], json=self.TEST_ROLES) - - role_list = self.client.roles.roles_for_user('foo', 'barrr') - [self.assertIsInstance(r, roles.Role) for r in role_list] - - def test_add_user_role(self): - self.stub_url('PUT', ['users', 'foo', 'roles', 'OS-KSADM', - 'barrr'], status_code=204) - - self.client.roles.add_user_role('foo', 'barrr') - - def test_add_user_role_tenant(self): - id_ = uuid.uuid4().hex - self.stub_url('PUT', ['tenants', id_, 'users', 'foo', 'roles', - 'OS-KSADM', 'barrr'], status_code=204) - - self.client.roles.add_user_role('foo', 'barrr', id_) - - def test_remove_user_role(self): - self.stub_url('DELETE', ['users', 'foo', 'roles', 'OS-KSADM', - 'barrr'], status_code=204) - self.client.roles.remove_user_role('foo', 'barrr') - - def test_remove_user_role_tenant(self): - id_ = uuid.uuid4().hex - self.stub_url('DELETE', ['tenants', id_, 'users', 'foo', - 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - self.client.roles.remove_user_role('foo', 'barrr', id_) diff --git a/keystoneclient/tests/unit/v2_0/test_service_catalog.py b/keystoneclient/tests/unit/v2_0/test_service_catalog.py deleted file mode 100644 index 612b7f0a..00000000 --- a/keystoneclient/tests/unit/v2_0/test_service_catalog.py +++ /dev/null @@ -1,207 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient import exceptions -from keystoneclient.tests.unit.v2_0 import client_fixtures -from keystoneclient.tests.unit.v2_0 import utils - - -class ServiceCatalogTest(utils.TestCase): - def setUp(self): - super(ServiceCatalogTest, self).setUp() - self.AUTH_RESPONSE_BODY = client_fixtures.auth_response_body() - - def test_building_a_service_catalog(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - self.assertEqual(sc.url_for(service_type='compute'), - "https://compute.north.host/v1/1234") - self.assertEqual(sc.url_for('tenantId', '1', service_type='compute'), - "https://compute.north.host/v1/1234") - self.assertEqual(sc.url_for('tenantId', '2', service_type='compute'), - "https://compute.north.host/v1.1/3456") - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, "region", - "South", service_type='compute') - - def test_service_catalog_endpoints(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - public_ep = sc.get_endpoints(service_type='compute', - endpoint_type='publicURL') - self.assertEqual(public_ep['compute'][1]['tenantId'], '2') - self.assertEqual(public_ep['compute'][1]['versionId'], '1.1') - self.assertEqual(public_ep['compute'][1]['internalURL'], - "https://compute.north.host/v1.1/3456") - - def test_service_catalog_regions(self): - self.AUTH_RESPONSE_BODY['access']['region_name'] = "North" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', endpoint_type='publicURL') - self.assertEqual(url, "https://image.north.host/v1/") - - self.AUTH_RESPONSE_BODY['access']['region_name'] = "South" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', endpoint_type='internalURL') - self.assertEqual(url, "https://image-internal.south.host/v1/") - - def test_service_catalog_empty(self): - self.AUTH_RESPONSE_BODY['access']['serviceCatalog'] = [] - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - self.assertRaises(exceptions.EmptyCatalog, - auth_ref.service_catalog.url_for, - service_type='image', - endpoint_type='internalURL') - - def test_service_catalog_get_endpoints_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - endpoints = sc.get_endpoints(service_type='image', region_name='North') - self.assertEqual(len(endpoints), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.north.host/v1/') - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.south.host/v1/') - - endpoints = sc.get_endpoints(service_type='compute') - self.assertEqual(len(endpoints['compute']), 2) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='North') - self.assertEqual(len(endpoints['compute']), 2) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='West') - self.assertEqual(len(endpoints['compute']), 0) - - def test_service_catalog_url_for_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', region_name='North') - self.assertEqual(url, 'https://image.north.host/v1/') - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, 'https://image.south.host/v1/') - - url = sc.url_for(service_type='compute', - region_name='North', - attr='versionId', - filter_value='1.1') - self.assertEqual(url, 'https://compute.north.host/v1.1/3456') - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_type='image', region_name='West') - - def test_servcie_catalog_get_url_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - urls = sc.get_urls(service_type='image') - self.assertEqual(len(urls), 2) - - urls = sc.get_urls(service_type='image', region_name='North') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], 'https://image.north.host/v1/') - - urls = sc.get_urls(service_type='image', region_name='South') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], 'https://image.south.host/v1/') - - urls = sc.get_urls(service_type='image', region_name='West') - self.assertIsNone(urls) - - def test_service_catalog_param_overrides_body_region(self): - self.AUTH_RESPONSE_BODY['access']['region_name'] = "North" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image') - self.assertEqual(url, 'https://image.north.host/v1/') - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, 'https://image.south.host/v1/') - - endpoints = sc.get_endpoints(service_type='image') - self.assertEqual(len(endpoints['image']), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.north.host/v1/') - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints['image']), 1) - self.assertEqual(endpoints['image'][0]['publicURL'], - 'https://image.south.host/v1/') - - def test_service_catalog_service_name(self): - auth_ref = access.AccessInfo.factory(resp=None, - body=self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_name='Image Servers', endpoint_type='public', - service_type='image', region_name='North') - self.assertEqual('https://image.north.host/v1/', url) - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_name='Image Servers', service_type='compute') - - urls = sc.get_urls(service_type='image', service_name='Image Servers', - endpoint_type='public') - - self.assertIn('https://image.north.host/v1/', urls) - self.assertIn('https://image.south.host/v1/', urls) - - urls = sc.get_urls(service_type='image', service_name='Servers', - endpoint_type='public') - - self.assertIsNone(urls) - - def test_service_catalog_multiple_service_types(self): - token = fixture.V2Token() - token.set_scope() - - for i in range(3): - s = token.add_service('compute') - s.add_endpoint(public='public-%d' % i, - admin='admin-%d' % i, - internal='internal-%d' % i, - region='region-%d' % i) - - auth_ref = access.AccessInfo.factory(resp=None, body=token) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='publicURL') - - self.assertEqual(set(['public-0', 'public-1', 'public-2']), set(urls)) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='publicURL', - region_name='region-1') - - self.assertEqual(('public-1', ), urls) diff --git a/keystoneclient/tests/unit/v2_0/test_services.py b/keystoneclient/tests/unit/v2_0/test_services.py deleted file mode 100644 index 72c54769..00000000 --- a/keystoneclient/tests/unit/v2_0/test_services.py +++ /dev/null @@ -1,129 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import services - - -class ServiceTests(utils.ClientTestCase): - def setUp(self): - super(ServiceTests, self).setUp() - - self.NOVA_SERVICE_ID = uuid.uuid4().hex - self.KEYSTONE_SERVICE_ID = uuid.uuid4().hex - - self.TEST_SERVICES = { - "OS-KSADM:services": { - "values": [ - { - "name": "nova", - "type": "compute", - "description": "Nova-compatible service.", - "id": self.NOVA_SERVICE_ID - }, - { - "name": "keystone", - "type": "identity", - "description": "Keystone-compatible service.", - "id": self.KEYSTONE_SERVICE_ID - }, - ], - }, - } - - def test_create_with_description(self): - req_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "description": "Swift-compatible service.", - } - } - service_id = uuid.uuid4().hex - resp_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "description": "Swift-compatible service.", - "id": service_id, - } - } - self.stub_url('POST', ['OS-KSADM', 'services'], json=resp_body) - - service = self.client.services.create( - req_body['OS-KSADM:service']['name'], - req_body['OS-KSADM:service']['type'], - req_body['OS-KSADM:service']['description']) - self.assertIsInstance(service, services.Service) - self.assertEqual(service.id, service_id) - self.assertEqual(service.name, req_body['OS-KSADM:service']['name']) - self.assertEqual(service.description, - req_body['OS-KSADM:service']['description']) - self.assertRequestBodyIs(json=req_body) - - def test_create_without_description(self): - req_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "description": None, - } - } - service_id = uuid.uuid4().hex - resp_body = { - "OS-KSADM:service": { - "name": "swift", - "type": "object-store", - "id": service_id, - "description": None, - } - } - self.stub_url('POST', ['OS-KSADM', 'services'], json=resp_body) - - service = self.client.services.create( - req_body['OS-KSADM:service']['name'], - req_body['OS-KSADM:service']['type'], - req_body['OS-KSADM:service']['description']) - self.assertIsInstance(service, services.Service) - self.assertEqual(service.id, service_id) - self.assertEqual(service.name, req_body['OS-KSADM:service']['name']) - self.assertIsNone(service.description) - self.assertRequestBodyIs(json=req_body) - - def test_delete(self): - self.stub_url('DELETE', - ['OS-KSADM', 'services', self.NOVA_SERVICE_ID], - status_code=204) - - self.client.services.delete(self.NOVA_SERVICE_ID) - - def test_get(self): - test_services = self.TEST_SERVICES['OS-KSADM:services']['values'][0] - - self.stub_url('GET', ['OS-KSADM', 'services', self.NOVA_SERVICE_ID], - json={'OS-KSADM:service': test_services}) - - service = self.client.services.get(self.NOVA_SERVICE_ID) - self.assertIsInstance(service, services.Service) - self.assertEqual(service.id, self.NOVA_SERVICE_ID) - self.assertEqual(service.name, 'nova') - self.assertEqual(service.type, 'compute') - - def test_list(self): - self.stub_url('GET', ['OS-KSADM', 'services'], - json=self.TEST_SERVICES) - - service_list = self.client.services.list() - [self.assertIsInstance(r, services.Service) - for r in service_list] diff --git a/keystoneclient/tests/unit/v2_0/test_tenants.py b/keystoneclient/tests/unit/v2_0/test_tenants.py deleted file mode 100644 index 5e78aa3b..00000000 --- a/keystoneclient/tests/unit/v2_0/test_tenants.py +++ /dev/null @@ -1,366 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1 import exceptions -from keystoneauth1 import fixture - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client -from keystoneclient.v2_0 import tenants -from keystoneclient.v2_0 import users - - -class TenantTests(utils.ClientTestCase): - def setUp(self): - super(TenantTests, self).setUp() - - self.INVIS_ID = uuid.uuid4().hex - self.DEMO_ID = uuid.uuid4().hex - self.ADMIN_ID = uuid.uuid4().hex - self.EXTRAS_ID = uuid.uuid4().hex - - self.TEST_TENANTS = { - "tenants": { - "values": [ - { - "enabled": True, - "description": "A description change!", - "name": "invisible_to_admin", - "id": self.INVIS_ID, - }, - { - "enabled": True, - "description": "None", - "name": "demo", - "id": self.DEMO_ID, - }, - { - "enabled": True, - "description": "None", - "name": "admin", - "id": self.ADMIN_ID, - }, - { - "extravalue01": "metadata01", - "enabled": True, - "description": "For testing extras", - "name": "test_extras", - "id": self.EXTRAS_ID, - } - ], - "links": [], - }, - } - - def test_create(self): - req_body = { - "tenant": { - "name": "tenantX", - "description": "Like tenant 9, but better.", - "enabled": True, - "extravalue01": "metadata01", - }, - } - id_ = uuid.uuid4().hex - resp_body = { - "tenant": { - "name": "tenantX", - "enabled": True, - "id": id_, - "description": "Like tenant 9, but better.", - "extravalue01": "metadata01", - } - } - self.stub_url('POST', ['tenants'], json=resp_body) - - tenant = self.client.tenants.create( - req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled'], - extravalue01=req_body['tenant']['extravalue01'], - name="don't overwrite priors") - self.assertIsInstance(tenant, tenants.Tenant) - self.assertEqual(tenant.id, id_) - self.assertEqual(tenant.name, "tenantX") - self.assertEqual(tenant.description, "Like tenant 9, but better.") - self.assertEqual(tenant.extravalue01, "metadata01") - self.assertRequestBodyIs(json=req_body) - - def test_duplicate_create(self): - req_body = { - "tenant": { - "name": "tenantX", - "description": "The duplicate tenant.", - "enabled": True - }, - } - resp_body = { - "error": { - "message": "Conflict occurred attempting to store project.", - "code": 409, - "title": "Conflict", - } - } - self.stub_url('POST', ['tenants'], status_code=409, json=resp_body) - - def create_duplicate_tenant(): - self.client.tenants.create(req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled']) - - self.assertRaises(exceptions.Conflict, create_duplicate_tenant) - - def test_delete(self): - self.stub_url('DELETE', ['tenants', self.ADMIN_ID], status_code=204) - self.client.tenants.delete(self.ADMIN_ID) - - def test_get(self): - resp = {'tenant': self.TEST_TENANTS['tenants']['values'][2]} - self.stub_url('GET', ['tenants', self.ADMIN_ID], json=resp) - - t = self.client.tenants.get(self.ADMIN_ID) - self.assertIsInstance(t, tenants.Tenant) - self.assertEqual(t.id, self.ADMIN_ID) - self.assertEqual(t.name, 'admin') - - def test_list(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list() - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_list_limit(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list(limit=1) - self.assertQueryStringIs('limit=1') - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_list_marker(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list(marker=1) - self.assertQueryStringIs('marker=1') - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_list_limit_marker(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list(limit=1, marker=1) - self.assertQueryStringIs('marker=1&limit=1') - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - def test_update(self): - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "I changed you!", - "enabled": False, - "extravalue01": "metadataChanged", - # "extraname": "dontoverwrite!", - }, - } - resp_body = { - "tenant": { - "name": "tenantX", - "enabled": False, - "id": self.EXTRAS_ID, - "description": "I changed you!", - "extravalue01": "metadataChanged", - }, - } - - self.stub_url('POST', ['tenants', self.EXTRAS_ID], json=resp_body) - - tenant = self.client.tenants.update( - req_body['tenant']['id'], - req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled'], - extravalue01=req_body['tenant']['extravalue01'], - name="don't overwrite priors") - self.assertIsInstance(tenant, tenants.Tenant) - self.assertRequestBodyIs(json=req_body) - self.assertEqual(tenant.id, self.EXTRAS_ID) - self.assertEqual(tenant.name, "tenantX") - self.assertEqual(tenant.description, "I changed you!") - self.assertFalse(tenant.enabled) - self.assertEqual(tenant.extravalue01, "metadataChanged") - - def test_update_empty_description(self): - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "", - "enabled": False, - }, - } - resp_body = { - "tenant": { - "name": "tenantX", - "enabled": False, - "id": self.EXTRAS_ID, - "description": "", - }, - } - self.stub_url('POST', ['tenants', self.EXTRAS_ID], json=resp_body) - - tenant = self.client.tenants.update(req_body['tenant']['id'], - req_body['tenant']['name'], - req_body['tenant']['description'], - req_body['tenant']['enabled']) - self.assertIsInstance(tenant, tenants.Tenant) - self.assertRequestBodyIs(json=req_body) - self.assertEqual(tenant.id, self.EXTRAS_ID) - self.assertEqual(tenant.name, "tenantX") - self.assertEqual(tenant.description, "") - self.assertFalse(tenant.enabled) - - def test_add_user(self): - self.stub_url('PUT', - ['tenants', self.EXTRAS_ID, 'users', 'foo', 'roles', - 'OS-KSADM', 'barrr'], - status_code=204) - - self.client.tenants.add_user(self.EXTRAS_ID, 'foo', 'barrr') - - def test_remove_user(self): - self.stub_url('DELETE', ['tenants', self.EXTRAS_ID, 'users', - 'foo', 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - - self.client.tenants.remove_user(self.EXTRAS_ID, 'foo', 'barrr') - - def test_tenant_add_user(self): - self.stub_url('PUT', ['tenants', self.EXTRAS_ID, 'users', - 'foo', 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "I changed you!", - "enabled": False, - }, - } - # make tenant object with manager - tenant = self.client.tenants.resource_class(self.client.tenants, - req_body['tenant']) - tenant.add_user('foo', 'barrr') - self.assertIsInstance(tenant, tenants.Tenant) - - def test_tenant_remove_user(self): - self.stub_url('DELETE', ['tenants', self.EXTRAS_ID, 'users', - 'foo', 'roles', 'OS-KSADM', 'barrr'], - status_code=204) - - req_body = { - "tenant": { - "id": self.EXTRAS_ID, - "name": "tenantX", - "description": "I changed you!", - "enabled": False, - }, - } - - # make tenant object with manager - tenant = self.client.tenants.resource_class(self.client.tenants, - req_body['tenant']) - tenant.remove_user('foo', 'barrr') - self.assertIsInstance(tenant, tenants.Tenant) - - def test_tenant_list_users(self): - tenant_id = uuid.uuid4().hex - user_id1 = uuid.uuid4().hex - user_id2 = uuid.uuid4().hex - - tenant_resp = { - 'tenant': { - 'name': uuid.uuid4().hex, - 'enabled': True, - 'id': tenant_id, - 'description': 'test tenant', - } - } - - users_resp = { - 'users': { - 'values': [ - { - 'email': uuid.uuid4().hex, - 'enabled': True, - 'id': user_id1, - 'name': uuid.uuid4().hex, - }, - { - 'email': uuid.uuid4().hex, - 'enabled': True, - 'id': user_id2, - 'name': uuid.uuid4().hex, - }, - ] - } - } - - self.stub_url('GET', ['tenants', tenant_id], json=tenant_resp) - self.stub_url('GET', - ['tenants', tenant_id, 'users'], - json=users_resp) - - tenant = self.client.tenants.get(tenant_id) - user_objs = tenant.list_users() - - for u in user_objs: - self.assertIsInstance(u, users.User) - - self.assertEqual(set([user_id1, user_id2]), - set([u.id for u in user_objs])) - - def test_list_tenants_use_admin_url(self): - self.stub_url('GET', ['tenants'], json=self.TEST_TENANTS) - - tenant_list = self.client.tenants.list() - self.assertEqual(self.TEST_URL + '/tenants', - self.requests_mock.last_request.url) - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - self.assertEqual(len(self.TEST_TENANTS['tenants']['values']), - len(tenant_list)) - - def test_list_tenants_fallback_to_auth_url(self): - new_auth_url = 'http://keystone.test:5000/v2.0' - - token = fixture.V2Token(token_id=self.TEST_TOKEN, - user_name=self.TEST_USER, - user_id=self.TEST_USER_ID) - - self.stub_auth(base_url=new_auth_url, json=token) - self.stub_url('GET', ['tenants'], base_url=new_auth_url, - json=self.TEST_TENANTS) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username=self.TEST_USER, - auth_url=new_auth_url, - password=uuid.uuid4().hex) - - self.assertIsNone(c.management_url) - tenant_list = c.tenants.list() - [self.assertIsInstance(t, tenants.Tenant) for t in tenant_list] - - self.assertEqual(len(self.TEST_TENANTS['tenants']['values']), - len(tenant_list)) diff --git a/keystoneclient/tests/unit/v2_0/test_tokens.py b/keystoneclient/tests/unit/v2_0/test_tokens.py deleted file mode 100644 index 58df7c21..00000000 --- a/keystoneclient/tests/unit/v2_0/test_tokens.py +++ /dev/null @@ -1,217 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1 import exceptions -from keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import client -from keystoneclient.v2_0 import tokens - - -class TokenTests(utils.ClientTestCase): - - def test_delete(self): - id_ = uuid.uuid4().hex - self.stub_url('DELETE', ['tokens', id_], status_code=204) - self.client.tokens.delete(id_) - - def test_user_password(self): - token_fixture = fixture.V2Token(user_name=self.TEST_USER) - self.stub_auth(json=token_fixture) - - password = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(username=self.TEST_USER, - password=password) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - req_body = { - 'auth': { - 'passwordCredentials': { - 'username': self.TEST_USER, - 'password': password, - } - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_with_token_id(self): - token_fixture = fixture.V2Token() - self.stub_auth(json=token_fixture) - - token_id = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(token=token_id) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - req_body = { - 'auth': { - 'token': { - 'id': token_id, - } - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_without_auth_params(self): - self.assertRaises(ValueError, self.client.tokens.authenticate) - self.assertRaises(ValueError, self.client.tokens.authenticate, - tenant_id=uuid.uuid4().hex) - - def test_with_tenant_id(self): - token_fixture = fixture.V2Token() - token_fixture.set_scope() - self.stub_auth(json=token_fixture) - - token_id = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(token=token_id, - tenant_id=tenant_id) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - tenant_data = {'id': token_fixture.tenant_id, - 'name': token_fixture.tenant_name} - self.assertEqual(tenant_data, token_ref.tenant) - - req_body = { - 'auth': { - 'token': { - 'id': token_id, - }, - 'tenantId': tenant_id - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_with_tenant_name(self): - token_fixture = fixture.V2Token() - token_fixture.set_scope() - self.stub_auth(json=token_fixture) - - token_id = uuid.uuid4().hex - tenant_name = uuid.uuid4().hex - token_ref = self.client.tokens.authenticate(token=token_id, - tenant_name=tenant_name) - - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - tenant_data = {'id': token_fixture.tenant_id, - 'name': token_fixture.tenant_name} - self.assertEqual(tenant_data, token_ref.tenant) - - req_body = { - 'auth': { - 'token': { - 'id': token_id, - }, - 'tenantName': tenant_name - } - } - - self.assertRequestBodyIs(json=req_body) - - def test_authenticate_use_admin_url(self): - token_fixture = fixture.V2Token() - token_fixture.set_scope() - self.stub_auth(json=token_fixture) - - token_ref = self.client.tokens.authenticate(token=uuid.uuid4().hex) - self.assertEqual(self.TEST_URL + '/tokens', - self.requests_mock.last_request.url) - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - def test_authenticate_fallback_to_auth_url(self): - new_auth_url = 'http://keystone.test:5000/v2.0' - - token_fixture = fixture.V2Token() - self.stub_auth(base_url=new_auth_url, json=token_fixture) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(username=self.TEST_USER, - auth_url=new_auth_url, - password=uuid.uuid4().hex) - - self.assertIsNone(c.management_url) - - token_ref = c.tokens.authenticate(token=uuid.uuid4().hex) - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(token_fixture.token_id, token_ref.id) - self.assertEqual(token_fixture.expires_str, token_ref.expires) - - def test_validate_token(self): - id_ = uuid.uuid4().hex - token_fixture = fixture.V2Token(token_id=id_) - self.stub_url('GET', ['tokens', id_], json=token_fixture) - - token_data = self.client.tokens.get_token_data(id_) - self.assertEqual(token_fixture, token_data) - - token_ref = self.client.tokens.validate(id_) - self.assertIsInstance(token_ref, tokens.Token) - self.assertEqual(id_, token_ref.id) - - def test_validate_token_invalid_token(self): - # If the token is invalid, typically a NotFound is raised. - - id_ = uuid.uuid4().hex - # The server is expected to return 404 if the token is invalid. - self.stub_url('GET', ['tokens', id_], status_code=404) - - self.assertRaises(exceptions.NotFound, - self.client.tokens.get_token_data, id_) - self.assertRaises(exceptions.NotFound, - self.client.tokens.validate, id_) - - def test_validate_token_access_info_with_token_id(self): - # Can validate a token passing a string token ID. - token_id = uuid.uuid4().hex - token_fixture = fixture.V2Token(token_id=token_id) - self.stub_url('GET', ['tokens', token_id], json=token_fixture) - access_info = self.client.tokens.validate_access_info(token_id) - self.assertIsInstance(access_info, access.AccessInfoV2) - self.assertEqual(token_id, access_info.auth_token) - - def test_validate_token_access_info_with_access_info(self): - # Can validate a token passing an access info. - token_id = uuid.uuid4().hex - token_fixture = fixture.V2Token(token_id=token_id) - self.stub_url('GET', ['tokens', token_id], json=token_fixture) - token = access.AccessInfo.factory(body=token_fixture) - access_info = self.client.tokens.validate_access_info(token) - self.assertIsInstance(access_info, access.AccessInfoV2) - self.assertEqual(token_id, access_info.auth_token) - - def test_get_revoked(self): - sample_revoked_response = {'signed': '-----BEGIN CMS-----\nMIIB...'} - self.stub_url('GET', ['tokens', 'revoked'], - json=sample_revoked_response) - resp = self.client.tokens.get_revoked() - self.assertEqual(sample_revoked_response, resp) diff --git a/keystoneclient/tests/unit/v2_0/test_users.py b/keystoneclient/tests/unit/v2_0/test_users.py deleted file mode 100644 index d6507388..00000000 --- a/keystoneclient/tests/unit/v2_0/test_users.py +++ /dev/null @@ -1,301 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v2_0 import utils -from keystoneclient.v2_0 import roles -from keystoneclient.v2_0 import users - - -class UserTests(utils.ClientTestCase): - def setUp(self): - super(UserTests, self).setUp() - self.ADMIN_USER_ID = uuid.uuid4().hex - self.DEMO_USER_ID = uuid.uuid4().hex - self.TEST_USERS = { - "users": { - "values": [ - { - "email": "None", - "enabled": True, - "id": self.ADMIN_USER_ID, - "name": "admin", - }, - { - "email": "None", - "enabled": True, - "id": self.DEMO_USER_ID, - "name": "demo", - }, - ] - } - } - - def test_create(self): - tenant_id = uuid.uuid4().hex - user_id = uuid.uuid4().hex - password = uuid.uuid4().hex - req_body = { - "user": { - "name": "gabriel", - "password": password, - "tenantId": tenant_id, - "email": "test@example.com", - "enabled": True, - } - } - - resp_body = { - "user": { - "name": "gabriel", - "enabled": True, - "tenantId": tenant_id, - "id": user_id, - "password": password, - "email": "test@example.com", - } - } - - self.stub_url('POST', ['users'], json=resp_body) - - user = self.client.users.create(req_body['user']['name'], - req_body['user']['password'], - req_body['user']['email'], - tenant_id=req_body['user']['tenantId'], - enabled=req_body['user']['enabled']) - self.assertIsInstance(user, users.User) - self.assertEqual(user.id, user_id) - self.assertEqual(user.name, "gabriel") - self.assertEqual(user.email, "test@example.com") - self.assertRequestBodyIs(json=req_body) - self.assertNotIn(password, self.logger.output) - - def test_create_user_without_email(self): - tenant_id = uuid.uuid4().hex - req_body = { - "user": { - "name": "gabriel", - "password": "test", - "tenantId": tenant_id, - "enabled": True, - "email": None, - } - } - - user_id = uuid.uuid4().hex - resp_body = { - "user": { - "name": "gabriel", - "enabled": True, - "tenantId": tenant_id, - "id": user_id, - "password": "test", - } - } - - self.stub_url('POST', ['users'], json=resp_body) - - user = self.client.users.create( - req_body['user']['name'], - req_body['user']['password'], - tenant_id=req_body['user']['tenantId'], - enabled=req_body['user']['enabled']) - self.assertIsInstance(user, users.User) - self.assertEqual(user.id, user_id) - self.assertEqual(user.name, "gabriel") - self.assertRequestBodyIs(json=req_body) - - def test_create_user_without_password(self): - user_name = 'test' - user_id = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - user_enabled = True - req_body = { - 'user': { - 'name': user_name, - 'password': None, - 'tenantId': tenant_id, - 'enabled': user_enabled, - 'email': None, - } - } - resp_body = { - 'user': { - 'name': user_name, - 'enabled': user_enabled, - 'tenantId': tenant_id, - 'id': user_id, - } - } - - self.stub_url('POST', ['users'], json=resp_body) - - user = self.client.users.create(user_name, tenant_id=tenant_id, - enabled=user_enabled) - self.assertIsInstance(user, users.User) - self.assertEqual(user_id, user.id) - self.assertEqual(user_name, user.name) - self.assertRequestBodyIs(json=req_body) - - def test_delete(self): - self.stub_url('DELETE', ['users', self.ADMIN_USER_ID], status_code=204) - self.client.users.delete(self.ADMIN_USER_ID) - - def test_get(self): - self.stub_url('GET', ['users', self.ADMIN_USER_ID], - json={'user': self.TEST_USERS['users']['values'][0]}) - - u = self.client.users.get(self.ADMIN_USER_ID) - self.assertIsInstance(u, users.User) - self.assertEqual(u.id, self.ADMIN_USER_ID) - self.assertEqual(u.name, 'admin') - - def test_list(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list() - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_list_limit(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list(limit=1) - self.assertQueryStringIs('limit=1') - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_list_marker(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list(marker='foo') - self.assertQueryStringIs('marker=foo') - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_list_limit_marker(self): - self.stub_url('GET', ['users'], json=self.TEST_USERS) - - user_list = self.client.users.list(limit=1, marker='foo') - - self.assertQueryStringIs('marker=foo&limit=1') - [self.assertIsInstance(u, users.User) for u in user_list] - - def test_update(self): - req_1 = { - "user": { - "email": "gabriel@example.com", - "name": "gabriel", - } - } - password = uuid.uuid4().hex - req_2 = { - "user": { - "password": password, - } - } - tenant_id = uuid.uuid4().hex - req_3 = { - "user": { - "tenantId": tenant_id, - } - } - req_4 = { - "user": { - "enabled": False, - } - } - - self.stub_url('PUT', ['users', self.DEMO_USER_ID], json=req_1) - self.stub_url('PUT', - ['users', self.DEMO_USER_ID, 'OS-KSADM', 'password'], - json=req_2) - self.stub_url('PUT', - ['users', self.DEMO_USER_ID, 'OS-KSADM', 'tenant'], - json=req_3) - self.stub_url('PUT', - ['users', self.DEMO_USER_ID, 'OS-KSADM', 'enabled'], - json=req_4) - - self.client.users.update(self.DEMO_USER_ID, - name='gabriel', - email='gabriel@example.com') - self.assertRequestBodyIs(json=req_1) - self.client.users.update_password(self.DEMO_USER_ID, password) - self.assertRequestBodyIs(json=req_2) - self.client.users.update_tenant(self.DEMO_USER_ID, tenant_id) - self.assertRequestBodyIs(json=req_3) - self.client.users.update_enabled(self.DEMO_USER_ID, False) - self.assertRequestBodyIs(json=req_4) - self.assertNotIn(password, self.logger.output) - - def test_update_own_password(self): - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - req_body = { - 'user': { - 'password': new_password, - 'original_password': old_password - } - } - resp_body = { - 'access': {} - } - self.stub_url('PATCH', - ['OS-KSCRUD', 'users', self.TEST_USER_ID], - json=resp_body) - - self.client.users.update_own_password(old_password, new_password) - self.assertRequestBodyIs(json=req_body) - self.assertNotIn(old_password, self.logger.output) - self.assertNotIn(new_password, self.logger.output) - - def test_user_role_listing(self): - user_id = uuid.uuid4().hex - role_id1 = uuid.uuid4().hex - role_id2 = uuid.uuid4().hex - tenant_id = uuid.uuid4().hex - - user_resp = { - 'user': { - 'id': user_id, - 'email': uuid.uuid4().hex, - 'name': uuid.uuid4().hex, - } - } - - roles_resp = { - 'roles': { - 'values': [ - { - 'name': uuid.uuid4().hex, - 'id': role_id1, - }, - { - 'name': uuid.uuid4().hex, - 'id': role_id2, - } - ] - } - } - - self.stub_url('GET', ['users', user_id], json=user_resp) - self.stub_url('GET', - ['tenants', tenant_id, 'users', user_id, 'roles'], - json=roles_resp) - - user = self.client.users.get(user_id) - role_objs = user.list_roles(tenant_id) - - for r in role_objs: - self.assertIsInstance(r, roles.Role) - - self.assertEqual(set([role_id1, role_id2]), - set([r.id for r in role_objs])) diff --git a/keystoneclient/tests/unit/v2_0/utils.py b/keystoneclient/tests/unit/v2_0/utils.py deleted file mode 100644 index 6532d71b..00000000 --- a/keystoneclient/tests/unit/v2_0/utils.py +++ /dev/null @@ -1,90 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils - - -class UnauthenticatedTestCase(utils.TestCase): - """Class used as base for unauthenticated calls.""" - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v2.0') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v2.0') - - -class TestCase(UnauthenticatedTestCase): - - TEST_ADMIN_IDENTITY_ENDPOINT = "http://127.0.0.1:35357/v2.0" - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "adminURL": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "internalURL": "http://127.0.0.1:8774/v1.0", - "publicURL": "http://cdn.admin-nets.local:8774/v1.0/" - }], - "type": "nova_compat", - "name": "nova_compat" - }, { - "endpoints": [{ - "adminURL": "http://nova/novapi/admin", - "region": "RegionOne", - "internalURL": "http://nova/novapi/internal", - "publicURL": "http://nova/novapi/public" - }], - "type": "compute", - "name": "nova" - }, { - "endpoints": [{ - "adminURL": "http://glance/glanceapi/admin", - "region": "RegionOne", - "internalURL": "http://glance/glanceapi/internal", - "publicURL": "http://glance/glanceapi/public" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "adminURL": TEST_ADMIN_IDENTITY_ENDPOINT, - "region": "RegionOne", - "internalURL": "http://127.0.0.1:5000/v2.0", - "publicURL": "http://127.0.0.1:5000/v2.0" - }], - "type": "identity", - "name": "keystone" - }, { - "endpoints": [{ - "adminURL": "http://swift/swiftapi/admin", - "region": "RegionOne", - "internalURL": "http://swift/swiftapi/internal", - "publicURL": "http://swift/swiftapi/public" - }], - "type": "object-store", - "name": "swift" - }] - - def stub_auth(self, **kwargs): - self.stub_url('POST', ['tokens'], **kwargs) - - -class ClientTestCase(utils.ClientTestCaseMixin, TestCase): - - scenarios = [ - ('original', - {'client_fixture_class': client_fixtures.OriginalV2}), - ('ksc-session', - {'client_fixture_class': client_fixtures.KscSessionV2}), - ('ksa-session', - {'client_fixture_class': client_fixtures.KsaSessionV2}), - ] diff --git a/keystoneclient/tests/unit/v3/__init__.py b/keystoneclient/tests/unit/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/keystoneclient/tests/unit/v3/client_fixtures.py b/keystoneclient/tests/unit/v3/client_fixtures.py deleted file mode 100644 index 8e86208e..00000000 --- a/keystoneclient/tests/unit/v3/client_fixtures.py +++ /dev/null @@ -1,159 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from __future__ import unicode_literals -import uuid - -from keystoneauth1 import fixture - - -def unscoped_token(**kwargs): - return fixture.V3Token(**kwargs) - - -def domain_scoped_token(**kwargs): - kwargs.setdefault('audit_chain_id', uuid.uuid4().hex) - f = fixture.V3Token(**kwargs) - if not f.domain_id: - f.set_domain_scope() - - f.add_role(name='admin') - f.add_role(name='member') - region = 'RegionOne' - - s = f.add_service('volume') - s.add_standard_endpoints(public='http://public.com:8776/v1/None', - internal='http://internal.com:8776/v1/None', - admin='http://admin.com:8776/v1/None', - region=region) - - s = f.add_service('image') - s.add_standard_endpoints(public='http://public.com:9292/v1', - internal='http://internal:9292/v1', - admin='http://admin:9292/v1', - region=region) - - s = f.add_service('compute') - s.add_standard_endpoints(public='http://public.com:8774/v1.1/None', - internal='http://internal:8774/v1.1/None', - admin='http://admin:8774/v1.1/None', - region=region) - - s = f.add_service('ec2') - s.add_standard_endpoints(public='http://public.com:8773/services/Cloud', - internal='http://internal:8773/services/Cloud', - admin='http://admin:8773/services/Admin', - region=region) - - s = f.add_service('identity') - s.add_standard_endpoints(public='http://public.com:5000/v3', - internal='http://internal:5000/v3', - admin='http://admin:35357/v3', - region=region) - - return f - - -def project_scoped_token(**kwargs): - kwargs.setdefault('audit_chain_id', uuid.uuid4().hex) - f = fixture.V3Token(**kwargs) - - if not f.project_id: - f.set_project_scope() - - f.add_role(name='admin') - f.add_role(name='member') - - region = 'RegionOne' - tenant = '225da22d3ce34b15877ea70b2a575f58' - - s = f.add_service('volume') - s.add_standard_endpoints(public='http://public.com:8776/v1/%s' % tenant, - internal='http://internal:8776/v1/%s' % tenant, - admin='http://admin:8776/v1/%s' % tenant, - region=region) - - s = f.add_service('image') - s.add_standard_endpoints(public='http://public.com:9292/v1', - internal='http://internal:9292/v1', - admin='http://admin:9292/v1', - region=region) - - s = f.add_service('compute') - s.add_standard_endpoints(public='http://public.com:8774/v2/%s' % tenant, - internal='http://internal:8774/v2/%s' % tenant, - admin='http://admin:8774/v2/%s' % tenant, - region=region) - - s = f.add_service('ec2') - s.add_standard_endpoints(public='http://public.com:8773/services/Cloud', - internal='http://internal:8773/services/Cloud', - admin='http://admin:8773/services/Admin', - region=region) - - s = f.add_service('identity') - s.add_standard_endpoints(public='http://public.com:5000/v3', - internal='http://internal:5000/v3', - admin='http://admin:35357/v3', - region=region) - - return f - - -AUTH_SUBJECT_TOKEN = uuid.uuid4().hex - -AUTH_RESPONSE_HEADERS = { - 'X-Subject-Token': AUTH_SUBJECT_TOKEN, -} - - -def auth_response_body(): - f = fixture.V3Token(audit_chain_id=uuid.uuid4().hex) - f.set_project_scope() - - f.add_role(name='admin') - f.add_role(name='member') - - s = f.add_service('compute', name='nova') - s.add_standard_endpoints( - public='https://compute.north.host/novapi/public', - internal='https://compute.north.host/novapi/internal', - admin='https://compute.north.host/novapi/admin', - region='North') - - s = f.add_service('object-store', name='swift') - s.add_standard_endpoints( - public='http://swift.north.host/swiftapi/public', - internal='http://swift.north.host/swiftapi/internal', - admin='http://swift.north.host/swiftapi/admin', - region='South') - - s = f.add_service('image', name='glance') - s.add_standard_endpoints( - public='http://glance.north.host/glanceapi/public', - internal='http://glance.north.host/glanceapi/internal', - admin='http://glance.north.host/glanceapi/admin', - region='North') - - s.add_standard_endpoints( - public='http://glance.south.host/glanceapi/public', - internal='http://glance.south.host/glanceapi/internal', - admin='http://glance.south.host/glanceapi/admin', - region='South') - - return f - - -def trust_token(): - f = fixture.V3Token(audit_chain_id=uuid.uuid4().hex) - f.set_trust_scope() - return f diff --git a/keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml b/keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml deleted file mode 100644 index 487bcac5..00000000 --- a/keystoneclient/tests/unit/v3/examples/xml/ADFS_RequestSecurityTokenResponse.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal - urn:uuid:487c064b-b7c6-4654-b4d4-715f9961170e - - - 2014-08-05T18:36:14.235Z - 2014-08-05T18:41:14.235Z - - - - - - - - 2014-08-05T18:36:14.063Z - 2014-08-05T19:36:14.063Z - - - - https://ltartari2.cern.ch:5000/Shibboleth.sso/ADFS - - - - - - - https://ltartari2.cern.ch:5000/Shibboleth.sso/ADFS - - - - - marek.denis@cern.ch - - urn:oasis:names:tc:SAML:1.0:cm:bearer - - - - marek.denis@cern.ch - - - marek.denis@cern.ch - - - madenis - - - CERN Users - - - Domain Users - occupants-bldg-31 - CERN-Direct-Employees - ca-dev-allowed - cernts-cerntstest-users - staf-fell-pjas-at-cern - ELG-CERN - student-club-new-members - pawel-dynamic-test-82 - - - Marek Kamil Denis - - - +5555555 - - - 31S-013 - - - Marek Kamil - - - Denis - - - CERN Registered - - - CERN - - - Normal - - - - - marek.denis@cern.ch - - urn:oasis:names:tc:SAML:1.0:cm:bearer - - - - - - - - - - - - - - EaZ/2d0KAY5un9akV3++Npyk6hBc8JuTYs2S3lSxUeQ= - - - CxYiYvNsbedhHdmDbb9YQCBy6Ppus3bNJdw2g2HLq0VU2yRhv23mUW05I89Hs4yG4OcCo0uOZ3zaeNFbSNXMW+Mr996tAXtujKjgyrCXNJAToE+gwltvGxwY1EluSbe3IzoSM3Ao87mKhxGOSzlDhuN7dQ9Rv6l/J4gUjbOO5SIX4pdZ6mVF7cHEfe9x+H8Lg15YjnElQUEaPi+NSW5jYTdtIpsB4ORxJvALuSt6+4doDYc9wuwBiWkEdnBHAQBINoKpAV2oy0/C85SBX3IdRhxUznmL5yEUmf8JvPccXecMPqJow0L43mnCdu74xPwU0as3MNfYQ10kLvHXHfIExg== - - - MIIIEjCCBfqgAwIBAgIKLYgjvQAAAAAAMDANBgkqhkiG9w0BAQsFADBRMRIwEAYKCZImiZPyLGQBGRYCY2gxFDASBgoJkiaJk/IsZAEZFgRjZXJuMSUwIwYDVQQDExxDRVJOIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMTEwODA4Mzg1NVoXDTIzMDcyOTA5MTkzOFowVjESMBAGCgmSJomT8ixkARkWAmNoMRQwEgYKCZImiZPyLGQBGRYEY2VybjESMBAGA1UECxMJY29tcHV0ZXJzMRYwFAYDVQQDEw1sb2dpbi5jZXJuLmNoMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6t1C0SGlLddL2M+ltffGioTnDT3eztOxlA9bAGuvB8/Rjym8en6+ET9boM02CyoR5Vpn8iElXVWccAExPIQEq70D6LPe86vb+tYhuKPeLfuICN9Z0SMQ4f+57vk61Co1/uw/8kPvXlyd+Ai8Dsn/G0hpH67bBI9VOQKfpJqclcSJuSlUB5PJffvMUpr29B0eRx8LKFnIHbDILSu6nVbFLcadtWIjbYvoKorXg3J6urtkz+zEDeYMTvA6ZGOFf/Xy5eGtroSq9csSC976tx+umKEPhXBA9AcpiCV9Cj5axN03Aaa+iTE36jpnjcd9d02dy5Q9jE2nUN6KXnB6qF6eQIDAQABo4ID5TCCA+EwPQYJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIg73QCYLtjQ2G7Ysrgd71N4WA0GIehd2yb4Wu9TkCAWQCARkwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIFoDBoBgNVHSAEYTBfMF0GCisGAQQBYAoEAQEwTzBNBggrBgEFBQcCARZBaHR0cDovL2NhLWRvY3MuY2Vybi5jaC9jYS1kb2NzL2NwLWNwcy9jZXJuLXRydXN0ZWQtY2EyLWNwLWNwcy5wZGYwJwYJKwYBBAGCNxUKBBowGDAKBggrBgEFBQcDAjAKBggrBgEFBQcDATAdBgNVHQ4EFgQUqtJcwUXasyM6sRaO5nCMFoFDenMwGAYDVR0RBBEwD4INbG9naW4uY2Vybi5jaDAfBgNVHSMEGDAWgBQdkBnqyM7MPI0UsUzZ7BTiYUADYTCCASoGA1UdHwSCASEwggEdMIIBGaCCARWgggERhkdodHRwOi8vY2FmaWxlcy5jZXJuLmNoL2NhZmlsZXMvY3JsL0NFUk4lMjBDZXJ0aWZpY2F0aW9uJTIwQXV0aG9yaXR5LmNybIaBxWxkYXA6Ly8vQ049Q0VSTiUyMENlcnRpZmljYXRpb24lMjBBdXRob3JpdHksQ049Q0VSTlBLSTA3LENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWNlcm4sREM9Y2g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIBVAYIKwYBBQUHAQEEggFGMIIBQjBcBggrBgEFBQcwAoZQaHR0cDovL2NhZmlsZXMuY2Vybi5jaC9jYWZpbGVzL2NlcnRpZmljYXRlcy9DRVJOJTIwQ2VydGlmaWNhdGlvbiUyMEF1dGhvcml0eS5jcnQwgbsGCCsGAQUFBzAChoGubGRhcDovLy9DTj1DRVJOJTIwQ2VydGlmaWNhdGlvbiUyMEF1dGhvcml0eSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jZXJuLERDPWNoP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jZXJuLmNoL29jc3AwDQYJKoZIhvcNAQELBQADggIBAGKZ3bknTCfNuh4TMaL3PuvBFjU8LQ5NKY9GLZvY2ibYMRk5Is6eWRgyUsy1UJRQdaQQPnnysqrGq8VRw/NIFotBBsA978/+jj7v4e5Kr4o8HvwAQNLBxNmF6XkDytpLL701FcNEGRqIsoIhNzihi2VBADLC9HxljEyPT52IR767TMk/+xTOqClceq3sq6WRD4m+xaWRUJyOhn+Pqr+wbhXIw4wzHC6X0hcLj8P9Povtm6VmKkN9JPuymMo/0+zSrUt2+TYfmbbEKYJSP0+sceQ76IKxxmSdKAr1qDNE8v+c3DvPM2PKmfivwaV2l44FdP8ulzqTgphkYcN1daa9Oc+qJeyu/eL7xWzk6Zq5R+jVrMlM0p1y2XczI7Hoc96TMOcbVnwgMcVqRM9p57VItn6XubYPR0C33i1yUZjkWbIfqEjq6Vev6lVgngOyzu+hqC/8SDyORA3dlF9aZOD13kPZdF/JRphHREQtaRydAiYRlE/WHTvOcY52jujDftUR6oY0eWaWkwSHbX+kDFx8IlR8UtQCUgkGHBGwnOYLIGu7SRDGSfOBOiVhxKoHWVk/pL6eKY2SkmyOmmgO4JnQGg95qeAOMG/EQZt/2x8GAavUqGvYy9dPFwFf08678hQqkjNSuex7UD0ku8OP1QKvpP44l6vZhFc6A5XqjdU9lus1 - - - - - - - - _c9e77bc4-a81b-4da7-88c2-72a6ba376d3f - - - - - _c9e77bc4-a81b-4da7-88c2-72a6ba376d3f - - - urn:oasis:names:tc:SAML:1.0:assertion - http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue - http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer - - - - \ No newline at end of file diff --git a/keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml b/keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml deleted file mode 100644 index 913252e7..00000000 --- a/keystoneclient/tests/unit/v3/examples/xml/ADFS_fault.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - http://www.w3.org/2005/08/addressing/soap/fault - urn:uuid:89c47849-2622-4cdc-bb06-1d46c89ed12d - - - - - s:Sender - - a:FailedAuthentication - - - - At least one security token in the message could not be validated. - - - - \ No newline at end of file diff --git a/keystoneclient/tests/unit/v3/saml2_fixtures.py b/keystoneclient/tests/unit/v3/saml2_fixtures.py deleted file mode 100644 index 3cf2e772..00000000 --- a/keystoneclient/tests/unit/v3/saml2_fixtures.py +++ /dev/null @@ -1,281 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -SP_SOAP_RESPONSE = six.b(""" - - - - -https://openstack4.local/shibboleth - - - - - -ss:mem:6f1f20fafbb38433467e9d477df67615 - - - https://openstack4.local/shibboleth - - - - -""") - - -SAML2_ASSERTION = six.b(""" - - - - - x= - - - - - -https://idp.testshib.org/idp/shibboleth - - - - - - - - - - - - - - -VALUE== - - -VALUE= - - -""") - -UNSCOPED_TOKEN_HEADER = 'UNSCOPED_TOKEN' - -UNSCOPED_TOKEN = { - "token": { - "issued_at": "2014-06-09T09:48:59.643406Z", - "extras": {}, - "methods": ["saml2"], - "expires_at": "2014-06-09T10:48:59.643375Z", - "user": { - "OS-FEDERATION": { - "identity_provider": { - "id": "testshib" - }, - "protocol": { - "id": "saml2" - }, - "groups": [ - {"id": "1764fa5cf69a49a4918131de5ce4af9a"} - ] - }, - "id": "testhib%20user", - "name": "testhib user" - } - } -} - -PROJECTS = { - "projects": [ - { - "domain_id": "37ef61", - "enabled": 'true', - "id": "12d706", - "links": { - "self": "http://identity:35357/v3/projects/12d706" - }, - "name": "a project name" - }, - { - "domain_id": "37ef61", - "enabled": 'true', - "id": "9ca0eb", - "links": { - "self": "http://identity:35357/v3/projects/9ca0eb" - }, - "name": "another project" - } - ], - "links": { - "self": "http://identity:35357/v3/auth/projects", - "previous": 'null', - "next": 'null' - } -} - -DOMAINS = { - "domains": [ - { - "description": "desc of domain", - "enabled": 'true', - "id": "37ef61", - "links": { - "self": "http://identity:35357/v3/domains/37ef61" - }, - "name": "my domain" - } - ], - "links": { - "self": "http://identity:35357/v3/auth/domains", - "previous": 'null', - "next": 'null' - } -} - -SAML_ENCODING = "" - -TOKEN_SAML_RESPONSE = """ - - - http://keystone.idp/v3/OS-FEDERATION/saml2/idp - - - - - - - http://keystone.idp/v3/OS-FEDERATION/saml2/idp - - - - - - - - - - - - 0KH2CxdkfzU+6eiRhTC+mbObUKI= - - - - - m2jh5gDvX/1k+4uKtbb08CHp2b9UWsLw - - - - ... - - - - - admin - - - - - - - - urn:oasis:names:tc:SAML:2.0:ac:classes:Password - - - http://keystone.idp/v3/OS-FEDERATION/saml2/idp - - - - - - admin - - - admin - - - admin - - - - -""" - -TOKEN_BASED_SAML = ''.join([SAML_ENCODING, TOKEN_SAML_RESPONSE]) - -ECP_ENVELOPE = """ - - - - ss:mem:1ddfe8b0f58341a5a840d2e8717b0737 - - - - {0} - - -""".format(TOKEN_SAML_RESPONSE) - -TOKEN_BASED_ECP = ''.join([SAML_ENCODING, ECP_ENVELOPE]) diff --git a/keystoneclient/tests/unit/v3/test_access.py b/keystoneclient/tests/unit/v3/test_access.py deleted file mode 100644 index 26ca8f15..00000000 --- a/keystoneclient/tests/unit/v3/test_access.py +++ /dev/null @@ -1,211 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime -import uuid - -from keystoneauth1 import fixture -from oslo_utils import timeutils - -from keystoneclient import access -from keystoneclient.tests.unit import utils as test_utils -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -TOKEN_RESPONSE = test_utils.test_response( - headers=client_fixtures.AUTH_RESPONSE_HEADERS -) -UNSCOPED_TOKEN = client_fixtures.unscoped_token() -DOMAIN_SCOPED_TOKEN = client_fixtures.domain_scoped_token() -PROJECT_SCOPED_TOKEN = client_fixtures.project_scoped_token() - - -class AccessInfoTest(utils.TestCase): - def test_building_unscoped_accessinfo(self): - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=UNSCOPED_TOKEN) - - self.assertTrue(auth_ref) - self.assertIn('methods', auth_ref) - self.assertNotIn('catalog', auth_ref) - - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, - auth_ref.auth_token) - self.assertEqual(UNSCOPED_TOKEN.user_name, auth_ref.username) - self.assertEqual(UNSCOPED_TOKEN.user_id, auth_ref.user_id) - - self.assertEqual(auth_ref.role_ids, []) - self.assertEqual(auth_ref.role_names, []) - - self.assertIsNone(auth_ref.project_name) - self.assertIsNone(auth_ref.project_id) - - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.auth_url) - with self.deprecations.expect_deprecations_here(): - self.assertIsNone(auth_ref.management_url) - - self.assertFalse(auth_ref.domain_scoped) - self.assertFalse(auth_ref.project_scoped) - - self.assertEqual(UNSCOPED_TOKEN.user_domain_id, - auth_ref.user_domain_id) - self.assertEqual(UNSCOPED_TOKEN.user_domain_name, - auth_ref.user_domain_name) - - self.assertIsNone(auth_ref.project_domain_id) - self.assertIsNone(auth_ref.project_domain_name) - - self.assertEqual(auth_ref.expires, timeutils.parse_isotime( - UNSCOPED_TOKEN['token']['expires_at'])) - self.assertEqual(auth_ref.issued, timeutils.parse_isotime( - UNSCOPED_TOKEN['token']['issued_at'])) - - self.assertEqual(auth_ref.expires, UNSCOPED_TOKEN.expires) - self.assertEqual(auth_ref.issued, UNSCOPED_TOKEN.issued) - - self.assertEqual(auth_ref.audit_id, UNSCOPED_TOKEN.audit_id) - self.assertIsNone(auth_ref.audit_chain_id) - self.assertIsNone(UNSCOPED_TOKEN.audit_chain_id) - - def test_will_expire_soon(self): - expires = timeutils.utcnow() + datetime.timedelta(minutes=5) - UNSCOPED_TOKEN['token']['expires_at'] = expires.isoformat() - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=UNSCOPED_TOKEN) - self.assertFalse(auth_ref.will_expire_soon(stale_duration=120)) - self.assertTrue(auth_ref.will_expire_soon(stale_duration=301)) - self.assertFalse(auth_ref.will_expire_soon()) - - def test_building_domain_scoped_accessinfo(self): - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=DOMAIN_SCOPED_TOKEN) - - self.assertTrue(auth_ref) - self.assertIn('methods', auth_ref) - self.assertIn('catalog', auth_ref) - self.assertTrue(auth_ref['catalog']) - - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, - auth_ref.auth_token) - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_name, auth_ref.username) - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_id, auth_ref.user_id) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.role_ids, auth_ref.role_ids) - self.assertEqual(DOMAIN_SCOPED_TOKEN.role_names, auth_ref.role_names) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.domain_name, auth_ref.domain_name) - self.assertEqual(DOMAIN_SCOPED_TOKEN.domain_id, auth_ref.domain_id) - - self.assertIsNone(auth_ref.project_name) - self.assertIsNone(auth_ref.project_id) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_domain_id, - auth_ref.user_domain_id) - self.assertEqual(DOMAIN_SCOPED_TOKEN.user_domain_name, - auth_ref.user_domain_name) - - self.assertIsNone(auth_ref.project_domain_id) - self.assertIsNone(auth_ref.project_domain_name) - - self.assertTrue(auth_ref.domain_scoped) - self.assertFalse(auth_ref.project_scoped) - - self.assertEqual(DOMAIN_SCOPED_TOKEN.audit_id, auth_ref.audit_id) - self.assertEqual(DOMAIN_SCOPED_TOKEN.audit_chain_id, - auth_ref.audit_chain_id) - - def test_building_project_scoped_accessinfo(self): - auth_ref = access.AccessInfo.factory(resp=TOKEN_RESPONSE, - body=PROJECT_SCOPED_TOKEN) - - self.assertTrue(auth_ref) - self.assertIn('methods', auth_ref) - self.assertIn('catalog', auth_ref) - self.assertTrue(auth_ref['catalog']) - - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, - auth_ref.auth_token) - self.assertEqual(PROJECT_SCOPED_TOKEN.user_name, auth_ref.username) - self.assertEqual(PROJECT_SCOPED_TOKEN.user_id, auth_ref.user_id) - - self.assertEqual(PROJECT_SCOPED_TOKEN.role_ids, auth_ref.role_ids) - self.assertEqual(PROJECT_SCOPED_TOKEN.role_names, auth_ref.role_names) - - self.assertIsNone(auth_ref.domain_name) - self.assertIsNone(auth_ref.domain_id) - - self.assertEqual(PROJECT_SCOPED_TOKEN.project_name, - auth_ref.project_name) - self.assertEqual(PROJECT_SCOPED_TOKEN.project_id, auth_ref.project_id) - - self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) - self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) - - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.auth_url, - ('http://public.com:5000/v3',)) - with self.deprecations.expect_deprecations_here(): - self.assertEqual(auth_ref.management_url, - ('http://admin:35357/v3',)) - - self.assertEqual(PROJECT_SCOPED_TOKEN.project_domain_id, - auth_ref.project_domain_id) - self.assertEqual(PROJECT_SCOPED_TOKEN.project_domain_name, - auth_ref.project_domain_name) - - self.assertEqual(PROJECT_SCOPED_TOKEN.user_domain_id, - auth_ref.user_domain_id) - self.assertEqual(PROJECT_SCOPED_TOKEN.user_domain_name, - auth_ref.user_domain_name) - - self.assertFalse(auth_ref.domain_scoped) - self.assertTrue(auth_ref.project_scoped) - - self.assertEqual(PROJECT_SCOPED_TOKEN.audit_id, auth_ref.audit_id) - self.assertEqual(PROJECT_SCOPED_TOKEN.audit_chain_id, - auth_ref.audit_chain_id) - - def test_oauth_access(self): - consumer_id = uuid.uuid4().hex - access_token_id = uuid.uuid4().hex - - token = fixture.V3Token() - token.set_project_scope() - token.set_oauth(access_token_id=access_token_id, - consumer_id=consumer_id) - - auth_ref = access.AccessInfo.factory(body=token) - - self.assertEqual(consumer_id, auth_ref.oauth_consumer_id) - self.assertEqual(access_token_id, auth_ref.oauth_access_token_id) - - self.assertEqual(consumer_id, auth_ref['OS-OAUTH1']['consumer_id']) - self.assertEqual(access_token_id, - auth_ref['OS-OAUTH1']['access_token_id']) - - def test_override_auth_token(self): - token = fixture.V3Token() - token.set_project_scope() - - new_auth_token = uuid.uuid4().hex - auth_ref = access.AccessInfo.factory(body=token, - auth_token=new_auth_token) - self.assertEqual(new_auth_token, auth_ref.auth_token) - - def test_federated_property_standard_token(self): - """Check if is_federated property returns expected value.""" - token = fixture.V3Token() - token.set_project_scope() - auth_ref = access.AccessInfo.factory(body=token) - self.assertFalse(auth_ref.is_federated) diff --git a/keystoneclient/tests/unit/v3/test_auth.py b/keystoneclient/tests/unit/v3/test_auth.py deleted file mode 100644 index 6549080f..00000000 --- a/keystoneclient/tests/unit/v3/test_auth.py +++ /dev/null @@ -1,372 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils -from testtools import testcase - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import client - - -class AuthenticateAgainstKeystoneTests(utils.TestCase): - def setUp(self): - super(AuthenticateAgainstKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "token": { - "methods": [ - "token", - "password" - ], - - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_TENANT_ID, - "name": self.TEST_TENANT_NAME - }, - "user": { - "domain": { - "id": self.TEST_DOMAIN_ID, - "name": self.TEST_DOMAIN_NAME - }, - "id": self.TEST_USER, - "name": self.TEST_USER - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": self.TEST_SERVICE_CATALOG - }, - } - self.TEST_REQUEST_BODY = { - "auth": { - "identity": { - "methods": ["password"], - "password": { - "user": { - "domain": { - "name": self.TEST_DOMAIN_NAME - }, - "name": self.TEST_USER, - "password": self.TEST_TOKEN - } - } - }, - "scope": { - "project": { - "id": self.TEST_TENANT_ID - }, - } - } - } - self.TEST_REQUEST_HEADERS = { - 'Content-Type': 'application/json', - 'User-Agent': 'python-keystoneclient' - } - self.TEST_RESPONSE_HEADERS = { - 'X-Subject-Token': self.TEST_TOKEN - } - - def test_authenticate_success(self): - TEST_TOKEN = "abcdef" - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password']['user']['domain'] - del ident['password']['user']['name'] - ident['password']['user']['id'] = self.TEST_USER - - self.stub_auth(json=self.TEST_RESPONSE_DICT, subject_token=TEST_TOKEN) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_id=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, TEST_TOKEN) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_failure(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - ident['password']['user']['password'] = 'bad_key' - error = {"unauthorized": {"message": "Unauthorized", - "code": "401"}} - - self.stub_auth(status_code=401, json=error) - - with testcase.ExpectedException(exceptions.Unauthorized): - with self.deprecations.expect_deprecations_here(): - client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password="bad_key", - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_redirect(self): - headers = {'Location': self.TEST_ADMIN_URL + '/auth/tokens'} - self.stub_auth(status_code=305, text='Use proxy', headers=headers) - - self.stub_auth(json=self.TEST_RESPONSE_DICT, - base_url=self.TEST_ADMIN_URL) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - - def test_authenticate_success_domain_username_password_scoped(self): - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - - def test_authenticate_success_userid_password_domain_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password']['user']['domain'] - del ident['password']['user']['name'] - ident['password']['user']['id'] = self.TEST_USER - - scope = self.TEST_REQUEST_BODY['auth']['scope'] - del scope['project'] - scope['domain'] = {} - scope['domain']['id'] = self.TEST_DOMAIN_ID - - token = self.TEST_RESPONSE_DICT['token'] - del token['project'] - token['domain'] = {} - token['domain']['id'] = self.TEST_DOMAIN_ID - token['domain']['name'] = self.TEST_DOMAIN_NAME - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_id=self.TEST_USER, - password=self.TEST_TOKEN, - domain_id=self.TEST_DOMAIN_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_domain_id, - self.TEST_DOMAIN_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_userid_password_project_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password']['user']['domain'] - del ident['password']['user']['name'] - ident['password']['user']['id'] = self.TEST_USER - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_id=self.TEST_USER, - password=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_tenant_id, - self.TEST_TENANT_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_password_unscoped(self): - del self.TEST_RESPONSE_DICT['token']['catalog'] - del self.TEST_REQUEST_BODY['auth']['scope'] - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, - username=self.TEST_USER, - password=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertNotIn('catalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_auth_url_token_authentication(self): - fake_token = 'fake_token' - fake_url = '/fake-url' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(auth_url=self.TEST_URL, - token=fake_token) - body = jsonutils.loads(self.requests_mock.last_request.body) - self.assertEqual(body['auth']['identity']['token']['id'], fake_token) - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - def test_authenticate_success_token_domain_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password'] - ident['methods'] = ['token'] - ident['token'] = {} - ident['token']['id'] = self.TEST_TOKEN - - scope = self.TEST_REQUEST_BODY['auth']['scope'] - del scope['project'] - scope['domain'] = {} - scope['domain']['id'] = self.TEST_DOMAIN_ID - - token = self.TEST_RESPONSE_DICT['token'] - del token['project'] - token['domain'] = {} - token['domain']['id'] = self.TEST_DOMAIN_ID - token['domain']['name'] = self.TEST_DOMAIN_NAME - - self.TEST_REQUEST_HEADERS['X-Auth-Token'] = self.TEST_TOKEN - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - domain_id=self.TEST_DOMAIN_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_domain_id, - self.TEST_DOMAIN_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_project_scoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password'] - ident['methods'] = ['token'] - ident['token'] = {} - ident['token']['id'] = self.TEST_TOKEN - self.TEST_REQUEST_HEADERS['X-Auth-Token'] = self.TEST_TOKEN - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - project_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_tenant_id, - self.TEST_TENANT_ID) - self.assertEqual(cs.management_url, - self.TEST_RESPONSE_DICT["token"]["catalog"][3] - ['endpoints'][2]["url"]) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_authenticate_success_token_unscoped(self): - ident = self.TEST_REQUEST_BODY['auth']['identity'] - del ident['password'] - ident['methods'] = ['token'] - ident['token'] = {} - ident['token']['id'] = self.TEST_TOKEN - del self.TEST_REQUEST_BODY['auth']['scope'] - del self.TEST_RESPONSE_DICT['token']['catalog'] - self.TEST_REQUEST_HEADERS['X-Auth-Token'] = self.TEST_TOKEN - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client(token=self.TEST_TOKEN, - auth_url=self.TEST_URL) - self.assertEqual(cs.auth_token, - self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) - self.assertNotIn('catalog', cs.service_catalog.catalog) - self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) - - def test_allow_override_of_auth_token(self): - fake_url = '/fake-url' - fake_token = 'fake_token' - fake_resp = {'result': True} - - self.stub_auth(json=self.TEST_RESPONSE_DICT) - self.stub_url('GET', [fake_url], json=fake_resp, - base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL) - - self.assertEqual(cl.auth_token, self.TEST_TOKEN) - - # the token returned from the authentication will be used - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) - - # then override that token and the new token shall be used - cl.auth_token = fake_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(fake_token, token) - - # if we clear that overridden token then we fall back to the original - del cl.auth_token - - resp, body = cl._adapter.get(fake_url) - self.assertEqual(fake_resp, body) - - token = self.requests_mock.last_request.headers.get('X-Auth-Token') - self.assertEqual(self.TEST_TOKEN, token) diff --git a/keystoneclient/tests/unit/v3/test_auth_manager.py b/keystoneclient/tests/unit/v3/test_auth_manager.py deleted file mode 100644 index 18579607..00000000 --- a/keystoneclient/tests/unit/v3/test_auth_manager.py +++ /dev/null @@ -1,64 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1 import fixture - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import auth - - -class AuthProjectsTest(utils.ClientTestCase): - - def setUp(self): - super(AuthProjectsTest, self).setUp() - - self.v3token = fixture.V3Token() - self.stub_auth(json=self.v3token) - - self.stub_url('GET', - [], - json={'version': fixture.V3Discovery(self.TEST_URL)}) - - def create_resource(self, id=None, name=None, **kwargs): - kwargs['id'] = id or uuid.uuid4().hex - kwargs['name'] = name or uuid.uuid4().hex - return kwargs - - def test_get_projects(self): - body = {'projects': [self.create_resource(), - self.create_resource(), - self.create_resource()]} - - self.stub_url('GET', ['auth', 'projects'], json=body) - - projects = self.client.auth.projects() - - self.assertEqual(3, len(projects)) - - for p in projects: - self.assertIsInstance(p, auth.Project) - - def test_get_domains(self): - body = {'domains': [self.create_resource(), - self.create_resource(), - self.create_resource()]} - - self.stub_url('GET', ['auth', 'domains'], json=body) - - domains = self.client.auth.domains() - - self.assertEqual(3, len(domains)) - - for d in domains: - self.assertIsInstance(d, auth.Domain) diff --git a/keystoneclient/tests/unit/v3/test_auth_oidc.py b/keystoneclient/tests/unit/v3/test_auth_oidc.py deleted file mode 100644 index b0140dd0..00000000 --- a/keystoneclient/tests/unit/v3/test_auth_oidc.py +++ /dev/null @@ -1,188 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from oslo_config import fixture as config -from six.moves import urllib -import testtools - -from keystoneclient.auth import conf -from keystoneclient.contrib.auth.v3 import oidc -from keystoneclient import session -from keystoneclient.tests.unit.v3 import utils - - -ACCESS_TOKEN_ENDPOINT_RESP = {"access_token": "z5H1ITZLlJVDHQXqJun", - "token_type": "bearer", - "expires_in": 3599, - "scope": "profile", - "refresh_token": "DCERsh83IAhu9bhavrp"} - -KEYSTONE_TOKEN_VALUE = uuid.uuid4().hex -UNSCOPED_TOKEN = { - "token": { - "issued_at": "2014-06-09T09:48:59.643406Z", - "extras": {}, - "methods": ["oidc"], - "expires_at": "2014-06-09T10:48:59.643375Z", - "user": { - "OS-FEDERATION": { - "identity_provider": { - "id": "bluepages" - }, - "protocol": { - "id": "oidc" - }, - "groups": [ - {"id": "1764fa5cf69a49a4918131de5ce4af9a"} - ] - }, - "id": "oidc_user%40example.com", - "name": "oidc_user@example.com" - } - } -} - - -class AuthenticateOIDCTests(utils.TestCase): - - GROUP = 'auth' - - def setUp(self): - super(AuthenticateOIDCTests, self).setUp() - - self.deprecations.expect_deprecations() - - self.conf_fixture = self.useFixture(config.Config()) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.session = session.Session() - - self.IDENTITY_PROVIDER = 'bluepages' - self.PROTOCOL = 'oidc' - self.USER_NAME = 'oidc_user@example.com' - self.PASSWORD = uuid.uuid4().hex - self.CLIENT_ID = uuid.uuid4().hex - self.CLIENT_SECRET = uuid.uuid4().hex - self.ACCESS_TOKEN_ENDPOINT = 'https://localhost:8020/oidc/token' - self.FEDERATION_AUTH_URL = '%s/%s' % ( - self.TEST_URL, - 'OS-FEDERATION/identity_providers/bluepages/protocols/oidc/auth') - - self.oidcplugin = oidc.OidcPassword( - self.TEST_URL, - self.IDENTITY_PROVIDER, - self.PROTOCOL, - username=self.USER_NAME, - password=self.PASSWORD, - client_id=self.CLIENT_ID, - client_secret=self.CLIENT_SECRET, - access_token_endpoint=self.ACCESS_TOKEN_ENDPOINT) - - @testtools.skip("TypeError: __init__() got an unexpected keyword" - " argument 'project_name'") - def test_conf_params(self): - """Ensure OpenID Connect config options work.""" - section = uuid.uuid4().hex - identity_provider = uuid.uuid4().hex - protocol = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - client_id = uuid.uuid4().hex - client_secret = uuid.uuid4().hex - access_token_endpoint = uuid.uuid4().hex - - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(oidc.OidcPassword.get_options(), - group=section) - self.conf_fixture.config(auth_plugin='v3oidcpassword', - identity_provider=identity_provider, - protocol=protocol, - username=username, - password=password, - client_id=client_id, - client_secret=client_secret, - access_token_endpoint=access_token_endpoint, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertEqual(identity_provider, a.identity_provider) - self.assertEqual(protocol, a.protocol) - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - self.assertEqual(client_id, a.client_id) - self.assertEqual(client_secret, a.client_secret) - self.assertEqual(access_token_endpoint, a.access_token_endpoint) - - def test_initial_call_to_get_access_token(self): - """Test initial call, expect JSON access token.""" - # Mock the output that creates the access token - self.requests_mock.post( - self.ACCESS_TOKEN_ENDPOINT, - json=ACCESS_TOKEN_ENDPOINT_RESP) - - # Prep all the values and send the request - grant_type = 'password' - scope = 'profile email' - client_auth = (self.CLIENT_ID, self.CLIENT_SECRET) - payload = {'grant_type': grant_type, 'username': self.USER_NAME, - 'password': self.PASSWORD, 'scope': scope} - res = self.oidcplugin._get_access_token(self.session, - client_auth, - payload, - self.ACCESS_TOKEN_ENDPOINT) - - # Verify the request matches the expected structure - self.assertEqual(self.ACCESS_TOKEN_ENDPOINT, res.request.url) - self.assertEqual('POST', res.request.method) - encoded_payload = urllib.parse.urlencode(payload) - self.assertEqual(encoded_payload, res.request.body) - - def test_second_call_to_protected_url(self): - """Test subsequent call, expect Keystone token.""" - # Mock the output that creates the keystone token - self.requests_mock.post( - self.FEDERATION_AUTH_URL, - json=UNSCOPED_TOKEN, - headers={'X-Subject-Token': KEYSTONE_TOKEN_VALUE}) - - # Prep all the values and send the request - access_token = uuid.uuid4().hex - headers = {'Authorization': 'Bearer ' + access_token} - res = self.oidcplugin._get_keystone_token(self.session, - headers, - self.FEDERATION_AUTH_URL) - - # Verify the request matches the expected structure - self.assertEqual(self.FEDERATION_AUTH_URL, res.request.url) - self.assertEqual('POST', res.request.method) - self.assertEqual(headers['Authorization'], - res.request.headers['Authorization']) - - def test_end_to_end_workflow(self): - """Test full OpenID Connect workflow.""" - # Mock the output that creates the access token - self.requests_mock.post( - self.ACCESS_TOKEN_ENDPOINT, - json=ACCESS_TOKEN_ENDPOINT_RESP) - - # Mock the output that creates the keystone token - self.requests_mock.post( - self.FEDERATION_AUTH_URL, - json=UNSCOPED_TOKEN, - headers={'X-Subject-Token': KEYSTONE_TOKEN_VALUE}) - - response = self.oidcplugin.get_unscoped_auth_ref(self.session) - self.assertEqual(KEYSTONE_TOKEN_VALUE, response.auth_token) diff --git a/keystoneclient/tests/unit/v3/test_auth_saml2.py b/keystoneclient/tests/unit/v3/test_auth_saml2.py deleted file mode 100644 index b74983af..00000000 --- a/keystoneclient/tests/unit/v3/test_auth_saml2.py +++ /dev/null @@ -1,714 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import uuid - -from lxml import etree -from oslo_config import fixture as config -import requests -from six.moves import urllib - -from keystoneclient.auth import conf -from keystoneclient.contrib.auth.v3 import saml2 -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import saml2_fixtures -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3.contrib.federation import saml as saml_manager - -ROOTDIR = os.path.dirname(os.path.abspath(__file__)) -XMLDIR = os.path.join(ROOTDIR, 'examples', 'xml/') - - -def make_oneline(s): - return etree.tostring(etree.XML(s)).replace(b'\n', b'') - - -def _load_xml(filename): - with open(XMLDIR + filename, 'rb') as f: - return make_oneline(f.read()) - - -class AuthenticateviaSAML2Tests(utils.TestCase): - - GROUP = 'auth' - - class _AuthenticatedResponse(object): - headers = { - 'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER - } - - def json(self): - return saml2_fixtures.UNSCOPED_TOKEN - - class _AuthenticatedResponseInvalidJson(_AuthenticatedResponse): - - def json(self): - raise ValueError() - - class _AuthentiatedResponseMissingTokenID(_AuthenticatedResponse): - headers = {} - - def setUp(self): - super(AuthenticateviaSAML2Tests, self).setUp() - - self.deprecations.expect_deprecations() - - self.conf_fixture = self.useFixture(config.Config()) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.session = session.Session() - - self.ECP_SP_EMPTY_REQUEST_HEADERS = { - 'Accept': 'text/html; application/vnd.paos+xml', - 'PAOS': ('ver="urn:liberty:paos:2003-08";' - '"urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp"') - } - - self.ECP_SP_SAML2_REQUEST_HEADERS = { - 'Content-Type': 'application/vnd.paos+xml' - } - - self.ECP_SAML2_NAMESPACES = { - 'ecp': 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp', - 'S': 'http://schemas.xmlsoap.org/soap/envelope/', - 'paos': 'urn:liberty:paos:2003-08' - } - self.ECP_RELAY_STATE = '//ecp:RelayState' - self.ECP_SERVICE_PROVIDER_CONSUMER_URL = ('/S:Envelope/S:Header/paos:' - 'Request/' - '@responseConsumerURL') - self.ECP_IDP_CONSUMER_URL = ('/S:Envelope/S:Header/ecp:Response/' - '@AssertionConsumerServiceURL') - self.IDENTITY_PROVIDER = 'testidp' - self.IDENTITY_PROVIDER_URL = 'http://local.url' - self.PROTOCOL = 'saml2' - self.FEDERATION_AUTH_URL = '%s/%s' % ( - self.TEST_URL, - 'OS-FEDERATION/identity_providers/testidp/protocols/saml2/auth') - self.SHIB_CONSUMER_URL = ('https://openstack4.local/' - 'Shibboleth.sso/SAML2/ECP') - - self.saml2plugin = saml2.Saml2UnscopedToken( - self.TEST_URL, - self.IDENTITY_PROVIDER, self.IDENTITY_PROVIDER_URL, - self.TEST_USER, self.TEST_TOKEN) - - def test_conf_params(self): - section = uuid.uuid4().hex - identity_provider = uuid.uuid4().hex - identity_provider_url = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(saml2.Saml2UnscopedToken.get_options(), - group=section) - self.conf_fixture.config(auth_plugin='v3unscopedsaml', - identity_provider=identity_provider, - identity_provider_url=identity_provider_url, - username=username, - password=password, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertEqual(identity_provider, a.identity_provider) - self.assertEqual(identity_provider_url, a.identity_provider_url) - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - - def test_initial_sp_call(self): - """Test initial call, expect SOAP message.""" - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - content=make_oneline(saml2_fixtures.SP_SOAP_RESPONSE)) - a = self.saml2plugin._send_service_provider_request(self.session) - - self.assertFalse(a) - - fixture_soap_response = make_oneline( - saml2_fixtures.SP_SOAP_RESPONSE) - - sp_soap_response = make_oneline( - etree.tostring(self.saml2plugin.saml2_authn_request)) - - error_msg = "Expected %s instead of %s" % (fixture_soap_response, - sp_soap_response) - - self.assertEqual(fixture_soap_response, sp_soap_response, error_msg) - - self.assertEqual( - self.saml2plugin.sp_response_consumer_url, self.SHIB_CONSUMER_URL, - "Expected consumer_url set to %s instead of %s" % ( - self.SHIB_CONSUMER_URL, - str(self.saml2plugin.sp_response_consumer_url))) - - def test_initial_sp_call_when_saml_authenticated(self): - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - a = self.saml2plugin._send_service_provider_request(self.session) - self.assertTrue(a) - self.assertEqual( - saml2_fixtures.UNSCOPED_TOKEN['token'], - self.saml2plugin.authenticated_response.json()['token']) - self.assertEqual( - saml2_fixtures.UNSCOPED_TOKEN_HEADER, - self.saml2plugin.authenticated_response.headers['X-Subject-Token']) - - def test_get_unscoped_token_when_authenticated(self): - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER, - 'Content-Type': 'application/json'}) - - token, token_body = self.saml2plugin._get_unscoped_token(self.session) - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], token_body) - - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, token) - - def test_initial_sp_call_invalid_response(self): - """Send initial SP HTTP request and receive wrong server response.""" - self.requests_mock.get(self.FEDERATION_AUTH_URL, - text='NON XML RESPONSE') - - self.assertRaises( - exceptions.AuthorizationFailure, - self.saml2plugin._send_service_provider_request, - self.session) - - def test_send_authn_req_to_idp(self): - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=saml2_fixtures.SAML2_ASSERTION) - - self.saml2plugin.sp_response_consumer_url = self.SHIB_CONSUMER_URL - self.saml2plugin.saml2_authn_request = etree.XML( - saml2_fixtures.SP_SOAP_RESPONSE) - self.saml2plugin._send_idp_saml2_authn_request(self.session) - - idp_response = make_oneline(etree.tostring( - self.saml2plugin.saml2_idp_authn_response)) - - saml2_assertion_oneline = make_oneline( - saml2_fixtures.SAML2_ASSERTION) - error = "Expected %s instead of %s" % (saml2_fixtures.SAML2_ASSERTION, - idp_response) - self.assertEqual(idp_response, saml2_assertion_oneline, error) - - def test_fail_basicauth_idp_authentication(self): - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, status_code=401) - - self.saml2plugin.sp_response_consumer_url = self.SHIB_CONSUMER_URL - self.saml2plugin.saml2_authn_request = etree.XML( - saml2_fixtures.SP_SOAP_RESPONSE) - self.assertRaises( - exceptions.Unauthorized, - self.saml2plugin._send_idp_saml2_authn_request, - self.session) - - def test_mising_username_password_in_plugin(self): - self.assertRaises(TypeError, - saml2.Saml2UnscopedToken, - self.TEST_URL, self.IDENTITY_PROVIDER, - self.IDENTITY_PROVIDER_URL) - - def test_send_authn_response_to_sp(self): - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - self.saml2plugin.relay_state = etree.XML( - saml2_fixtures.SP_SOAP_RESPONSE).xpath( - self.ECP_RELAY_STATE, namespaces=self.ECP_SAML2_NAMESPACES)[0] - - self.saml2plugin.saml2_idp_authn_response = etree.XML( - saml2_fixtures.SAML2_ASSERTION) - - self.saml2plugin.idp_response_consumer_url = self.SHIB_CONSUMER_URL - self.saml2plugin._send_service_provider_saml2_authn_response( - self.session) - token_json = self.saml2plugin.authenticated_response.json()['token'] - token = self.saml2plugin.authenticated_response.headers[ - 'X-Subject-Token'] - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], - token_json) - - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, - token) - - def test_consumer_url_mismatch_success(self): - self.saml2plugin._check_consumer_urls( - self.session, self.SHIB_CONSUMER_URL, - self.SHIB_CONSUMER_URL) - - def test_consumer_url_mismatch(self): - self.requests_mock.post(self.SHIB_CONSUMER_URL) - invalid_consumer_url = uuid.uuid4().hex - self.assertRaises( - exceptions.ValidationError, - self.saml2plugin._check_consumer_urls, - self.session, self.SHIB_CONSUMER_URL, - invalid_consumer_url) - - def test_custom_302_redirection(self): - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - text='BODY', - headers={'location': self.FEDERATION_AUTH_URL}, - status_code=302) - - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - self.session.redirect = False - response = self.session.post( - self.SHIB_CONSUMER_URL, data='CLIENT BODY') - self.assertEqual(302, response.status_code) - self.assertEqual(self.FEDERATION_AUTH_URL, - response.headers['location']) - - response = self.saml2plugin._handle_http_ecp_redirect( - self.session, response, 'GET') - - self.assertEqual(self.FEDERATION_AUTH_URL, response.request.url) - self.assertEqual('GET', response.request.method) - - def test_custom_303_redirection(self): - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - text='BODY', - headers={'location': self.FEDERATION_AUTH_URL}, - status_code=303) - - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) - - self.session.redirect = False - response = self.session.post( - self.SHIB_CONSUMER_URL, data='CLIENT BODY') - self.assertEqual(303, response.status_code) - self.assertEqual(self.FEDERATION_AUTH_URL, - response.headers['location']) - - response = self.saml2plugin._handle_http_ecp_redirect( - self.session, response, 'GET') - - self.assertEqual(self.FEDERATION_AUTH_URL, response.request.url) - self.assertEqual('GET', response.request.method) - - def test_end_to_end_workflow(self): - self.requests_mock.get( - self.FEDERATION_AUTH_URL, - content=make_oneline(saml2_fixtures.SP_SOAP_RESPONSE)) - - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=saml2_fixtures.SAML2_ASSERTION) - - self.requests_mock.post( - self.SHIB_CONSUMER_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER, - 'Content-Type': 'application/json'}) - - self.session.redirect = False - response = self.saml2plugin.get_auth_ref(self.session) - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER, - response.auth_token) - - -class ScopeFederationTokenTests(AuthenticateviaSAML2Tests): - - TEST_TOKEN = client_fixtures.AUTH_SUBJECT_TOKEN - - def setUp(self): - super(ScopeFederationTokenTests, self).setUp() - - self.PROJECT_SCOPED_TOKEN_JSON = client_fixtures.project_scoped_token() - self.PROJECT_SCOPED_TOKEN_JSON['methods'] = ['saml2'] - - # for better readability - self.TEST_TENANT_ID = self.PROJECT_SCOPED_TOKEN_JSON.project_id - self.TEST_TENANT_NAME = self.PROJECT_SCOPED_TOKEN_JSON.project_name - - self.DOMAIN_SCOPED_TOKEN_JSON = client_fixtures.domain_scoped_token() - self.DOMAIN_SCOPED_TOKEN_JSON['methods'] = ['saml2'] - - # for better readability - self.TEST_DOMAIN_ID = self.DOMAIN_SCOPED_TOKEN_JSON.domain_id - self.TEST_DOMAIN_NAME = self.DOMAIN_SCOPED_TOKEN_JSON.domain_name - - self.saml2_scope_plugin = saml2.Saml2ScopedToken( - self.TEST_URL, saml2_fixtures.UNSCOPED_TOKEN_HEADER, - project_id=self.TEST_TENANT_ID) - - def test_scope_saml2_token_to_project(self): - self.stub_auth(json=self.PROJECT_SCOPED_TOKEN_JSON) - - token = self.saml2_scope_plugin.get_auth_ref(self.session) - self.assertTrue(token.project_scoped, "Received token is not scoped") - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token) - self.assertEqual(self.TEST_TENANT_ID, token.project_id) - self.assertEqual(self.TEST_TENANT_NAME, token.project_name) - - def test_scope_saml2_token_to_invalid_project(self): - self.stub_auth(status_code=401) - self.saml2_scope_plugin.project_id = uuid.uuid4().hex - self.saml2_scope_plugin.project_name = None - self.assertRaises(exceptions.Unauthorized, - self.saml2_scope_plugin.get_auth_ref, - self.session) - - def test_scope_saml2_token_to_invalid_domain(self): - self.stub_auth(status_code=401) - self.saml2_scope_plugin.project_id = None - self.saml2_scope_plugin.project_name = None - self.saml2_scope_plugin.domain_id = uuid.uuid4().hex - self.saml2_scope_plugin.domain_name = None - self.assertRaises(exceptions.Unauthorized, - self.saml2_scope_plugin.get_auth_ref, - self.session) - - def test_scope_saml2_token_to_domain(self): - self.stub_auth(json=self.DOMAIN_SCOPED_TOKEN_JSON) - token = self.saml2_scope_plugin.get_auth_ref(self.session) - self.assertTrue(token.domain_scoped, "Received token is not scoped") - self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token) - self.assertEqual(self.TEST_DOMAIN_ID, token.domain_id) - self.assertEqual(self.TEST_DOMAIN_NAME, token.domain_name) - - def test_dont_set_project_nor_domain(self): - self.saml2_scope_plugin.project_id = None - self.saml2_scope_plugin.domain_id = None - self.assertRaises(exceptions.ValidationError, - saml2.Saml2ScopedToken, - self.TEST_URL, client_fixtures.AUTH_SUBJECT_TOKEN) - - -class AuthenticateviaADFSTests(utils.TestCase): - - GROUP = 'auth' - - NAMESPACES = { - 's': 'http://www.w3.org/2003/05/soap-envelope', - 'trust': 'http://docs.oasis-open.org/ws-sx/ws-trust/200512', - 'wsa': 'http://www.w3.org/2005/08/addressing', - 'wsp': 'http://schemas.xmlsoap.org/ws/2004/09/policy', - 'a': 'http://www.w3.org/2005/08/addressing', - 'o': ('http://docs.oasis-open.org/wss/2004/01/oasis' - '-200401-wss-wssecurity-secext-1.0.xsd') - } - - USER_XPATH = ('/s:Envelope/s:Header' - '/o:Security' - '/o:UsernameToken' - '/o:Username') - PASSWORD_XPATH = ('/s:Envelope/s:Header' - '/o:Security' - '/o:UsernameToken' - '/o:Password') - ADDRESS_XPATH = ('/s:Envelope/s:Body' - '/trust:RequestSecurityToken' - '/wsp:AppliesTo/wsa:EndpointReference' - '/wsa:Address') - TO_XPATH = ('/s:Envelope/s:Header' - '/a:To') - - @property - def _uuid4(self): - return '4b911420-4982-4009-8afc-5c596cd487f5' - - def setUp(self): - super(AuthenticateviaADFSTests, self).setUp() - - self.deprecations.expect_deprecations() - - self.conf_fixture = self.useFixture(config.Config()) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.session = session.Session(session=requests.Session()) - - self.IDENTITY_PROVIDER = 'adfs' - self.IDENTITY_PROVIDER_URL = ('http://adfs.local/adfs/service/trust/13' - '/usernamemixed') - self.FEDERATION_AUTH_URL = '%s/%s' % ( - self.TEST_URL, - 'OS-FEDERATION/identity_providers/adfs/protocols/saml2/auth') - self.SP_ENDPOINT = 'https://openstack4.local/Shibboleth.sso/ADFS' - - self.adfsplugin = saml2.ADFSUnscopedToken( - self.TEST_URL, self.IDENTITY_PROVIDER, - self.IDENTITY_PROVIDER_URL, self.SP_ENDPOINT, - self.TEST_USER, self.TEST_TOKEN) - - self.ADFS_SECURITY_TOKEN_RESPONSE = _load_xml( - 'ADFS_RequestSecurityTokenResponse.xml') - self.ADFS_FAULT = _load_xml('ADFS_fault.xml') - - def test_conf_params(self): - section = uuid.uuid4().hex - identity_provider = uuid.uuid4().hex - identity_provider_url = uuid.uuid4().hex - sp_endpoint = uuid.uuid4().hex - username = uuid.uuid4().hex - password = uuid.uuid4().hex - self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - - self.conf_fixture.register_opts(saml2.ADFSUnscopedToken.get_options(), - group=section) - self.conf_fixture.config(auth_plugin='v3unscopedadfs', - identity_provider=identity_provider, - identity_provider_url=identity_provider_url, - service_provider_endpoint=sp_endpoint, - username=username, - password=password, - group=section) - - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) - self.assertEqual(identity_provider, a.identity_provider) - self.assertEqual(identity_provider_url, a.identity_provider_url) - self.assertEqual(sp_endpoint, a.service_provider_endpoint) - self.assertEqual(username, a.username) - self.assertEqual(password, a.password) - - def test_get_adfs_security_token(self): - """Test ADFSUnscopedToken._get_adfs_security_token().""" - self.requests_mock.post( - self.IDENTITY_PROVIDER_URL, - content=make_oneline(self.ADFS_SECURITY_TOKEN_RESPONSE), - status_code=200) - - self.adfsplugin._prepare_adfs_request() - self.adfsplugin._get_adfs_security_token(self.session) - - adfs_response = etree.tostring(self.adfsplugin.adfs_token) - fixture_response = self.ADFS_SECURITY_TOKEN_RESPONSE - - self.assertEqual(fixture_response, adfs_response) - - def test_adfs_request_user(self): - self.adfsplugin._prepare_adfs_request() - user = self.adfsplugin.prepared_request.xpath( - self.USER_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.TEST_USER, user.text) - - def test_adfs_request_password(self): - self.adfsplugin._prepare_adfs_request() - password = self.adfsplugin.prepared_request.xpath( - self.PASSWORD_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.TEST_TOKEN, password.text) - - def test_adfs_request_to(self): - self.adfsplugin._prepare_adfs_request() - to = self.adfsplugin.prepared_request.xpath( - self.TO_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.IDENTITY_PROVIDER_URL, to.text) - - def test_prepare_adfs_request_address(self): - self.adfsplugin._prepare_adfs_request() - address = self.adfsplugin.prepared_request.xpath( - self.ADDRESS_XPATH, namespaces=self.NAMESPACES)[0] - self.assertEqual(self.SP_ENDPOINT, address.text) - - def test_prepare_sp_request(self): - assertion = etree.XML(self.ADFS_SECURITY_TOKEN_RESPONSE) - assertion = assertion.xpath( - saml2.ADFSUnscopedToken.ADFS_ASSERTION_XPATH, - namespaces=saml2.ADFSUnscopedToken.ADFS_TOKEN_NAMESPACES) - assertion = assertion[0] - assertion = etree.tostring(assertion) - - assertion = assertion.replace( - b'http://docs.oasis-open.org/ws-sx/ws-trust/200512', - b'http://schemas.xmlsoap.org/ws/2005/02/trust') - assertion = urllib.parse.quote(assertion) - assertion = 'wa=wsignin1.0&wresult=' + assertion - - self.adfsplugin.adfs_token = etree.XML( - self.ADFS_SECURITY_TOKEN_RESPONSE) - self.adfsplugin._prepare_sp_request() - - self.assertEqual(assertion, self.adfsplugin.encoded_assertion) - - def test_get_adfs_security_token_authn_fail(self): - """Test proper parsing XML fault after bad authentication. - - An exceptions.AuthorizationFailure should be raised including - error message from the XML message indicating where was the problem. - """ - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=make_oneline(self.ADFS_FAULT), - status_code=500) - - self.adfsplugin._prepare_adfs_request() - self.assertRaises(exceptions.AuthorizationFailure, - self.adfsplugin._get_adfs_security_token, - self.session) - # TODO(marek-denis): Python3 tests complain about missing 'message' - # attributes - # self.assertEqual('a:FailedAuthentication', e.message) - - def test_get_adfs_security_token_bad_response(self): - """Test proper handling HTTP 500 and mangled (non XML) response. - - This should never happen yet, keystoneclient should be prepared - and correctly raise exceptions.InternalServerError once it cannot - parse XML fault message - """ - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=b'NOT XML', - status_code=500) - self.adfsplugin._prepare_adfs_request() - self.assertRaises(exceptions.InternalServerError, - self.adfsplugin._get_adfs_security_token, - self.session) - - # TODO(marek-denis): Need to figure out how to properly send cookies - # from the request_uri() method. - def _send_assertion_to_service_provider(self): - """Test whether SP issues a cookie.""" - cookie = uuid.uuid4().hex - - self.requests_mock.post(self.SP_ENDPOINT, - headers={"set-cookie": cookie}, - status_code=302) - - self.adfsplugin.adfs_token = self._build_adfs_request() - self.adfsplugin._prepare_sp_request() - self.adfsplugin._send_assertion_to_service_provider(self.session) - - self.assertEqual(1, len(self.session.session.cookies)) - - def test_send_assertion_to_service_provider_bad_status(self): - self.requests_mock.post(self.SP_ENDPOINT, status_code=500) - - self.adfsplugin.adfs_token = etree.XML( - self.ADFS_SECURITY_TOKEN_RESPONSE) - self.adfsplugin._prepare_sp_request() - - self.assertRaises( - exceptions.InternalServerError, - self.adfsplugin._send_assertion_to_service_provider, - self.session) - - def test_access_sp_no_cookies_fail(self): - # There are no cookies in the session initially, and - # _access_service_provider requires a cookie in the session. - self.assertRaises(exceptions.AuthorizationFailure, - self.adfsplugin._access_service_provider, - self.session) - - def test_check_valid_token_when_authenticated(self): - self.requests_mock.get(self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers=client_fixtures.AUTH_RESPONSE_HEADERS) - - # _access_service_provider requires a cookie in the session. - cookie = requests.cookies.create_cookie( - name=self.getUniqueString(), value=self.getUniqueString()) - self.session.session.cookies.set_cookie(cookie) - - self.adfsplugin._access_service_provider(self.session) - response = self.adfsplugin.authenticated_response - - self.assertEqual(client_fixtures.AUTH_RESPONSE_HEADERS, - response.headers) - - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], - response.json()['token']) - - def test_end_to_end_workflow(self): - self.requests_mock.post(self.IDENTITY_PROVIDER_URL, - content=self.ADFS_SECURITY_TOKEN_RESPONSE, - status_code=200) - self.requests_mock.post(self.SP_ENDPOINT, - headers={"set-cookie": 'x'}, - status_code=302) - self.requests_mock.get(self.FEDERATION_AUTH_URL, - json=saml2_fixtures.UNSCOPED_TOKEN, - headers=client_fixtures.AUTH_RESPONSE_HEADERS) - - # NOTE(marek-denis): We need to mimic this until self.requests_mock can - # issue cookies properly. - cookie = requests.cookies.create_cookie( - name=self.getUniqueString(), value=self.getUniqueString()) - self.session.session.cookies.set_cookie(cookie) - - token, token_json = self.adfsplugin._get_unscoped_token(self.session) - self.assertEqual(token, client_fixtures.AUTH_SUBJECT_TOKEN) - self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN['token'], token_json) - - -class SAMLGenerationTests(utils.ClientTestCase): - - def setUp(self): - super(SAMLGenerationTests, self).setUp() - self.manager = self.client.federation.saml - self.SAML2_FULL_URL = ''.join([self.TEST_URL, - saml_manager.SAML2_ENDPOINT]) - self.ECP_FULL_URL = ''.join([self.TEST_URL, - saml_manager.ECP_ENDPOINT]) - - def test_saml_create(self): - """Test that a token can be exchanged for a SAML assertion.""" - token_id = uuid.uuid4().hex - service_provider_id = uuid.uuid4().hex - - # Mock the returned text for '/auth/OS-FEDERATION/saml2 - self.requests_mock.post(self.SAML2_FULL_URL, - text=saml2_fixtures.TOKEN_BASED_SAML) - - text = self.manager.create_saml_assertion(service_provider_id, - token_id) - - # Ensure returned text is correct - self.assertEqual(saml2_fixtures.TOKEN_BASED_SAML, text) - - # Ensure request headers and body are correct - req_json = self.requests_mock.last_request.json() - self.assertEqual(token_id, req_json['auth']['identity']['token']['id']) - self.assertEqual(service_provider_id, - req_json['auth']['scope']['service_provider']['id']) - self.assertRequestHeaderEqual('Content-Type', 'application/json') - - def test_ecp_create(self): - """Test that a token can be exchanged for an ECP wrapped assertion.""" - token_id = uuid.uuid4().hex - service_provider_id = uuid.uuid4().hex - - # Mock returned text for '/auth/OS-FEDERATION/saml2/ecp - self.requests_mock.post(self.ECP_FULL_URL, - text=saml2_fixtures.TOKEN_BASED_ECP) - - text = self.manager.create_ecp_assertion(service_provider_id, - token_id) - - # Ensure returned text is correct - self.assertEqual(saml2_fixtures.TOKEN_BASED_ECP, text) - - # Ensure request headers and body are correct - req_json = self.requests_mock.last_request.json() - self.assertEqual(token_id, req_json['auth']['identity']['token']['id']) - self.assertEqual(service_provider_id, - req_json['auth']['scope']['service_provider']['id']) - self.assertRequestHeaderEqual('Content-Type', 'application/json') diff --git a/keystoneclient/tests/unit/v3/test_client.py b/keystoneclient/tests/unit/v3/test_client.py deleted file mode 100644 index feb921a5..00000000 --- a/keystoneclient/tests/unit/v3/test_client.py +++ /dev/null @@ -1,270 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import json -import uuid - - -from keystoneauth1 import session as auth_session -from keystoneclient.auth import token_endpoint -from keystoneclient import exceptions -from keystoneclient import session -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import client - - -class KeystoneClientTest(utils.TestCase): - - def test_unscoped_init(self): - token = client_fixtures.unscoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_domain_name=token.user_domain_name, - username=token.user_name, - password='password', - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - self.assertFalse(c.has_service_catalog()) - - self.assertEqual(token.user_id, c.get_user_id(session=None)) - self.assertIsNone(c.get_project_id(session=None)) - - def test_domain_scoped_init(self): - token = client_fixtures.domain_scoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=token.user_id, - password='password', - domain_name=token.domain_name, - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - self.assertTrue(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - self.assertEqual(token.domain_id, c.auth_domain_id) - - def test_project_scoped_init(self): - token = client_fixtures.project_scoped_token() - self.stub_auth(json=token), - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=token.user_id, - password='password', - user_domain_name=token.user_domain_name, - project_name=token.project_name, - auth_url=self.TEST_URL) - self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertTrue(c.auth_ref.project_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - self.assertEqual(token.project_id, c.auth_tenant_id) - self.assertEqual(token.user_id, c.get_user_id(session=None)) - self.assertEqual(token.project_id, c.get_project_id(session=None)) - - def test_auth_ref_load(self): - token = client_fixtures.project_scoped_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=token.user_id, - password='password', - project_id=token.project_id, - auth_url=self.TEST_URL) - cache = json.dumps(c.auth_ref) - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache)) - self.assertIsNotNone(new_client.auth_ref) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertEqual(token.user_name, new_client.username) - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v3') - - def test_auth_ref_load_with_overridden_arguments(self): - new_auth_url = 'https://newkeystone.com/v3' - - user_id = uuid.uuid4().hex - user_name = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - first = client_fixtures.project_scoped_token(user_id=user_id, - user_name=user_name, - project_id=project_id) - second = client_fixtures.project_scoped_token(user_id=user_id, - user_name=user_name, - project_id=project_id) - self.stub_auth(json=first) - self.stub_auth(json=second, base_url=new_auth_url) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_id=user_id, - password='password', - project_id=project_id, - auth_url=self.TEST_URL) - cache = json.dumps(c.auth_ref) - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - new_client = client.Client(auth_ref=json.loads(cache), - auth_url=new_auth_url) - self.assertIsNotNone(new_client.auth_ref) - self.assertFalse(new_client.auth_ref.domain_scoped) - self.assertTrue(new_client.auth_ref.project_scoped) - self.assertEqual(new_auth_url, new_client.auth_url) - self.assertEqual(user_name, new_client.username) - self.assertIsNone(new_client.password) - self.assertEqual(new_client.management_url, - 'http://admin:35357/v3') - - def test_trust_init(self): - token = client_fixtures.trust_token() - self.stub_auth(json=token) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - c = client.Client(user_domain_name=token.user_domain_name, - username=token.user_name, - password='password', - auth_url=self.TEST_URL, - trust_id=token.trust_id) - self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.domain_scoped) - self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(token.trust_id, c.auth_ref.trust_id) - self.assertEqual(token.trustee_user_id, c.auth_ref.trustee_user_id) - self.assertEqual(token.trustor_user_id, c.auth_ref.trustor_user_id) - self.assertTrue(c.auth_ref.trust_scoped) - self.assertEqual(token.user_id, c.auth_user_id) - - def test_init_err_no_auth_url(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - username='exampleuser', - password='password') - - def _management_url_is_updated(self, fixture, **kwargs): - second = copy.deepcopy(fixture) - first_url = 'http://admin:35357/v3' - second_url = "http://secondurl:%d/v3'" - - for entry in second['token']['catalog']: - if entry['type'] == 'identity': - entry['endpoints'] = [{ - 'url': second_url % 5000, - 'region': 'RegionOne', - 'interface': 'public' - }, { - 'url': second_url % 5000, - 'region': 'RegionOne', - 'interface': 'internal' - }, { - 'url': second_url % 35357, - 'region': 'RegionOne', - 'interface': 'admin' - }] - - self.stub_auth(response_list=[{'json': fixture}, {'json': second}]) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cl = client.Client(username='exampleuser', - password='password', - auth_url=self.TEST_URL, - **kwargs) - self.assertEqual(cl.management_url, first_url) - - with self.deprecations.expect_deprecations_here(): - cl.authenticate() - self.assertEqual(cl.management_url, second_url % 35357) - - def test_management_url_is_updated_with_project(self): - self._management_url_is_updated(client_fixtures.project_scoped_token(), - project_name='exampleproject') - - def test_management_url_is_updated_with_domain(self): - self._management_url_is_updated(client_fixtures.domain_scoped_token(), - domain_name='exampledomain') - - def test_client_with_region_name_passes_to_service_catalog(self): - # NOTE(jamielennox): this is deprecated behaviour that should be - # removed ASAP, however must remain compatible. - self.deprecations.expect_deprecations() - - self.stub_auth(json=client_fixtures.auth_response_body()) - - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='North') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'http://glance.north.host/glanceapi/public') - - cl = client.Client(username='exampleuser', - password='password', - project_name='exampleproject', - auth_url=self.TEST_URL, - region_name='South') - self.assertEqual(cl.service_catalog.url_for(service_type='image'), - 'http://glance.south.host/glanceapi/public') - - def test_client_without_auth_params(self): - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - self.assertRaises(exceptions.AuthorizationFailure, - client.Client, - project_name='exampleproject', - auth_url=self.TEST_URL) - - def test_client_params(self): - with self.deprecations.expect_deprecations_here(): - sess = session.Session() - auth = token_endpoint.Token('a', 'b') - - opts = {'auth': auth, - 'connect_retries': 50, - 'endpoint_override': uuid.uuid4().hex, - 'interface': uuid.uuid4().hex, - 'region_name': uuid.uuid4().hex, - 'service_name': uuid.uuid4().hex, - 'user_agent': uuid.uuid4().hex, - } - - cl = client.Client(session=sess, **opts) - - for k, v in opts.items(): - self.assertEqual(v, getattr(cl._adapter, k)) - - self.assertEqual('identity', cl._adapter.service_type) - self.assertEqual((3, 0), cl._adapter.version) - - def test_empty_service_catalog_param(self): - # Client().service_catalog should return None if the client is not - # authenticated - sess = auth_session.Session() - cl = client.Client(session=sess) - self.assertIsNone(cl.service_catalog) diff --git a/keystoneclient/tests/unit/v3/test_credentials.py b/keystoneclient/tests/unit/v3/test_credentials.py deleted file mode 100644 index 0efc3dfb..00000000 --- a/keystoneclient/tests/unit/v3/test_credentials.py +++ /dev/null @@ -1,33 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import credentials - - -class CredentialTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(CredentialTests, self).setUp() - self.key = 'credential' - self.collection_key = 'credentials' - self.model = credentials.Credential - self.manager = self.client.credentials - - def new_ref(self, **kwargs): - kwargs = super(CredentialTests, self).new_ref(**kwargs) - kwargs.setdefault('blob', uuid.uuid4().hex) - kwargs.setdefault('project_id', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('user_id', uuid.uuid4().hex) - return kwargs diff --git a/keystoneclient/tests/unit/v3/test_discover.py b/keystoneclient/tests/unit/v3/test_discover.py deleted file mode 100644 index f54b2f9c..00000000 --- a/keystoneclient/tests/unit/v3/test_discover.py +++ /dev/null @@ -1,82 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.generic import client -from keystoneclient.tests.unit.v3 import utils - - -class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): - def setUp(self): - super(DiscoverKeystoneTests, self).setUp() - self.TEST_RESPONSE_DICT = { - "versions": { - "values": [{"id": "v3.0", - "status": "beta", - "updated": "2013-03-06T00:00:00Z", - "links": [ - {"rel": "self", - "href": "http://127.0.0.1:5000/v3.0/", }, - {"rel": "describedby", - "type": "text/html", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/3/" - "content/", }, - {"rel": "describedby", - "type": "application/pdf", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/3/" - "identity-dev-guide-3.pdf", }, - ]}, - {"id": "v2.0", - "status": "beta", - "updated": "2013-03-06T00:00:00Z", - "links": [ - {"rel": "self", - "href": "http://127.0.0.1:5000/v2.0/", }, - {"rel": "describedby", - "type": "text/html", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/" - "content/", }, - {"rel": "describedby", - "type": "application/pdf", - "href": "https://docs.openstack.org/api/" - "openstack-identity-service/2.0/" - "identity-dev-guide-2.0.pdf", } - ]}], - }, - } - self.TEST_REQUEST_HEADERS = { - 'User-Agent': 'python-keystoneclient', - 'Accept': 'application/json', - } - - def test_get_version_local(self): - self.requests_mock.get("http://localhost:35357/", - status_code=300, - json=self.TEST_RESPONSE_DICT) - - # Creating a HTTPClient not using session is deprecated. - with self.deprecations.expect_deprecations_here(): - cs = client.Client() - versions = cs.discover() - self.assertIsInstance(versions, dict) - self.assertIn('message', versions) - self.assertIn('v3.0', versions) - self.assertEqual( - versions['v3.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][0]['links'][0] - ['href']) - self.assertEqual( - versions['v2.0']['url'], - self.TEST_RESPONSE_DICT['versions']['values'][1]['links'][0] - ['href']) diff --git a/keystoneclient/tests/unit/v3/test_domain_configs.py b/keystoneclient/tests/unit/v3/test_domain_configs.py deleted file mode 100644 index 2a7df092..00000000 --- a/keystoneclient/tests/unit/v3/test_domain_configs.py +++ /dev/null @@ -1,96 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import domain_configs - - -class DomainConfigsTests(utils.ClientTestCase, utils.CrudTests): - """Test domain config database management.""" - - def setUp(self): - super(DomainConfigsTests, self).setUp() - self.key = 'config' - self.model = domain_configs.DomainConfig - self.manager = self.client.domain_configs - - def new_ref(self, **kwargs): - config_groups = {'identity': {uuid.uuid4().hex: uuid.uuid4().hex}, - 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}} - kwargs.setdefault('config', config_groups) - return kwargs - - def _assert_resource_attributes(self, resource, req_ref): - for attr in req_ref: - self.assertEqual( - getattr(resource, attr), - req_ref[attr], - 'Expected different %s' % attr) - - def test_create(self): - domain_id = uuid.uuid4().hex - config = self.new_ref() - - self.stub_url('PUT', - parts=['domains', domain_id, 'config'], - json=config, status_code=201) - res = self.manager.create(domain_id, config) - self._assert_resource_attributes(res, config['config']) - self.assertEntityRequestBodyIs(config) - - def test_update(self): - domain_id = uuid.uuid4().hex - config = self.new_ref() - - self.stub_url('PATCH', - parts=['domains', domain_id, 'config'], - json=config, status_code=200) - res = self.manager.update(domain_id, config) - self._assert_resource_attributes(res, config['config']) - self.assertEntityRequestBodyIs(config) - - def test_get(self): - domain_id = uuid.uuid4().hex - config = self.new_ref() - config = config['config'] - - self.stub_entity('GET', - parts=['domains', domain_id, 'config'], - entity=config) - res = self.manager.get(domain_id) - self._assert_resource_attributes(res, config) - - def test_delete(self): - domain_id = uuid.uuid4().hex - self.stub_url('DELETE', - parts=['domains', domain_id, 'config'], - status_code=204) - self.manager.delete(domain_id) - - def test_list(self): - # List not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.list) - - def test_list_by_id(self): - # List not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.list) - - def test_list_params(self): - # List not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.list) - - def test_find(self): - # Find not supported for domain config - self.assertRaises(exceptions.MethodNotImplemented, self.manager.find) diff --git a/keystoneclient/tests/unit/v3/test_domains.py b/keystoneclient/tests/unit/v3/test_domains.py deleted file mode 100644 index 72a7b883..00000000 --- a/keystoneclient/tests/unit/v3/test_domains.py +++ /dev/null @@ -1,53 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import domains - - -class DomainTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(DomainTests, self).setUp() - self.key = 'domain' - self.collection_key = 'domains' - self.model = domains.Domain - self.manager = self.client.domains - - def new_ref(self, **kwargs): - kwargs = super(DomainTests, self).new_ref(**kwargs) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_filter_for_default_domain_by_id(self): - ref = self.new_ref(id='default') - super(DomainTests, self).test_list_by_id( - ref=ref, - id=ref['id']) - - def test_list_filter_name(self): - super(DomainTests, self).test_list(name='adomain123') - - def test_list_filter_enabled(self): - super(DomainTests, self).test_list(enabled=True) - - def test_list_filter_disabled(self): - # False is converted to '0' ref bug #1267530 - expected_query = {'enabled': '0'} - super(DomainTests, self).test_list(expected_query=expected_query, - enabled=False) - - def test_update_enabled_defaults_to_none(self): - super(DomainTests, self).test_update( - req_ref={'name': uuid.uuid4().hex}) diff --git a/keystoneclient/tests/unit/v3/test_ec2.py b/keystoneclient/tests/unit/v3/test_ec2.py deleted file mode 100644 index 66679f60..00000000 --- a/keystoneclient/tests/unit/v3/test_ec2.py +++ /dev/null @@ -1,107 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import ec2 - - -class EC2Tests(utils.ClientTestCase): - - def test_create(self): - user_id = 'usr' - tenant_id = 'tnt' - req_body = { - "tenant_id": tenant_id, - } - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('POST', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - cred = self.client.ec2.create(user_id, tenant_id) - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - self.assertRequestBodyIs(json=req_body) - - def test_get(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credential": { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2', 'access'], json=resp_body) - - cred = self.client.ec2.get(user_id, 'access') - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_list(self): - user_id = 'usr' - tenant_id = 'tnt' - resp_body = { - "credentials": { - "values": [ - { - "access": "access", - "secret": "secret", - "tenant_id": tenant_id, - "created": "12/12/12", - "enabled": True, - }, - { - "access": "another", - "secret": "key", - "tenant_id": tenant_id, - "created": "12/12/31", - "enabled": True, - } - ] - } - } - self.stub_url('GET', ['users', user_id, 'credentials', - 'OS-EC2'], json=resp_body) - - creds = self.client.ec2.list(user_id) - self.assertEqual(len(creds), 2) - cred = creds[0] - self.assertIsInstance(cred, ec2.EC2) - self.assertEqual(cred.tenant_id, tenant_id) - self.assertEqual(cred.enabled, True) - self.assertEqual(cred.access, 'access') - self.assertEqual(cred.secret, 'secret') - - def test_delete(self): - user_id = 'usr' - access = 'access' - self.stub_url('DELETE', ['users', user_id, 'credentials', - 'OS-EC2', access], status_code=204) - self.client.ec2.delete(user_id, access) diff --git a/keystoneclient/tests/unit/v3/test_endpoint_filter.py b/keystoneclient/tests/unit/v3/test_endpoint_filter.py deleted file mode 100644 index 62e89cb3..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoint_filter.py +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils - - -class EndpointTestUtils(object): - """Mixin class with shared methods between Endpoint Filter & Policy.""" - - def new_ref(self, **kwargs): - # copied from CrudTests as we need to create endpoint and project - # refs for our tests. EndpointFilter is not exactly CRUD API. - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def new_endpoint_ref(self, **kwargs): - # copied from EndpointTests as we need endpoint refs for our tests - kwargs = self.new_ref(**kwargs) - kwargs.setdefault('interface', 'public') - kwargs.setdefault('region', uuid.uuid4().hex) - kwargs.setdefault('service_id', uuid.uuid4().hex) - kwargs.setdefault('url', uuid.uuid4().hex) - return kwargs - - def new_endpoint_group_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('filters') - return kwargs - - -class EndpointFilterTests(utils.ClientTestCase, EndpointTestUtils): - """Test project-endpoint associations (a.k.a. EndpointFilter Extension). - - Endpoint filter provides associations between service endpoints and - projects. These assciations are then used to create ad-hoc catalogs for - each project-scoped token request. - - """ - - def setUp(self): - super(EndpointFilterTests, self).setUp() - self.manager = self.client.endpoint_filter - - def new_project_ref(self, **kwargs): - # copied from ProjectTests as we need project refs for our tests - kwargs = self.new_ref(**kwargs) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_add_endpoint_to_project_via_id(self): - endpoint_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('PUT', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints', endpoint_id], - status_code=201) - - self.manager.add_endpoint_to_project(project=project_id, - endpoint=endpoint_id) - - def test_add_endpoint_to_project_via_obj(self): - project_ref = self.new_project_ref() - endpoint_ref = self.new_endpoint_ref() - project = self.client.projects.resource_class(self.client.projects, - project_ref, - loaded=True) - endpoint = self.client.endpoints.resource_class(self.client.endpoints, - endpoint_ref, - loaded=True) - - self.stub_url('PUT', - [self.manager.OS_EP_FILTER_EXT, - 'projects', project_ref['id'], - 'endpoints', endpoint_ref['id']], - status_code=201) - - self.manager.add_endpoint_to_project(project=project, - endpoint=endpoint) - - def test_delete_endpoint_from_project(self): - endpoint_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('DELETE', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints', endpoint_id], - status_code=201) - - self.manager.delete_endpoint_from_project(project=project_id, - endpoint=endpoint_id) - - def test_check_endpoint_in_project(self): - endpoint_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('HEAD', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints', endpoint_id], - status_code=201) - - self.manager.check_endpoint_in_project(project=project_id, - endpoint=endpoint_id) - - def test_list_endpoints_for_project(self): - project_id = uuid.uuid4().hex - endpoints = {'endpoints': [self.new_endpoint_ref(), - self.new_endpoint_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'projects', project_id, - 'endpoints'], - json=endpoints, - status_code=200) - - endpoints_resp = self.manager.list_endpoints_for_project( - project=project_id) - - expected_endpoint_ids = [ - endpoint['id'] for endpoint in endpoints['endpoints']] - actual_endpoint_ids = [endpoint.id for endpoint in endpoints_resp] - self.assertEqual(expected_endpoint_ids, actual_endpoint_ids) - - def test_list_projects_for_endpoint(self): - endpoint_id = uuid.uuid4().hex - projects = {'projects': [self.new_project_ref(), - self.new_project_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'endpoints', endpoint_id, - 'projects'], - json=projects, - status_code=200) - - projects_resp = self.manager.list_projects_for_endpoint( - endpoint=endpoint_id) - - expected_project_ids = [ - project['id'] for project in projects['projects']] - actual_project_ids = [project.id for project in projects_resp] - self.assertEqual(expected_project_ids, actual_project_ids) - - def test_list_projects_for_endpoint_group(self): - endpoint_group_id = uuid.uuid4().hex - projects = {'projects': [self.new_project_ref(), - self.new_project_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects'], - json=projects, - status_code=200) - - projects_resp = self.manager.list_projects_for_endpoint_group( - endpoint_group=endpoint_group_id) - - expected_project_ids = [ - project['id'] for project in projects['projects']] - actual_project_ids = [project.id for project in projects_resp] - self.assertEqual(expected_project_ids, actual_project_ids) - - def test_list_projects_for_endpoint_group_value_error(self): - self.assertRaises(ValueError, - self.manager.list_projects_for_endpoint_group, - endpoint_group='') - self.assertRaises(ValueError, - self.manager.list_projects_for_endpoint_group, - endpoint_group=None) - - def test_list_endpoint_groups_for_project(self): - project_id = uuid.uuid4().hex - endpoint_groups = { - 'endpoint_groups': [self.new_endpoint_group_ref(), - self.new_endpoint_group_ref()]} - self.stub_url('GET', - [self.manager.OS_EP_FILTER_EXT, 'projects', - project_id, 'endpoint_groups'], - json=endpoint_groups, - status_code=200) - - endpoint_groups_resp = self.manager.list_endpoint_groups_for_project( - project=project_id) - - expected_endpoint_group_ids = [ - endpoint_group['id'] for endpoint_group - in endpoint_groups['endpoint_groups'] - ] - actual_endpoint_group_ids = [ - endpoint_group.id for endpoint_group in endpoint_groups_resp - ] - self.assertEqual(expected_endpoint_group_ids, - actual_endpoint_group_ids) - - def test_list_endpoint_groups_for_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.list_endpoint_groups_for_project, - project=value) - - def test_add_endpoint_group_to_project(self): - endpoint_group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('PUT', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects', project_id], - status_code=201) - - self.manager.add_endpoint_group_to_project( - project=project_id, endpoint_group=endpoint_group_id) - - def test_add_endpoint_group_to_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.add_endpoint_group_to_project, - project=value, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.add_endpoint_group_to_project, - project=uuid.uuid4().hex, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.add_endpoint_group_to_project, - project=value, - endpoint_group=uuid.uuid4().hex) - - def test_check_endpoint_group_in_project(self): - endpoint_group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('HEAD', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects', project_id], - status_code=201) - - self.manager.check_endpoint_group_in_project( - project=project_id, endpoint_group=endpoint_group_id) - - def test_check_endpoint_group_in_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.check_endpoint_group_in_project, - project=value, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.check_endpoint_group_in_project, - project=uuid.uuid4().hex, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.check_endpoint_group_in_project, - project=value, - endpoint_group=uuid.uuid4().hex) - - def test_delete_endpoint_group_from_project(self): - endpoint_group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.stub_url('DELETE', - [self.manager.OS_EP_FILTER_EXT, 'endpoint_groups', - endpoint_group_id, 'projects', project_id], - status_code=201) - - self.manager.delete_endpoint_group_from_project( - project=project_id, endpoint_group=endpoint_group_id) - - def test_delete_endpoint_group_from_project_value_error(self): - for value in ('', None): - self.assertRaises(ValueError, - self.manager.delete_endpoint_group_from_project, - project=value, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.delete_endpoint_group_from_project, - project=uuid.uuid4().hex, - endpoint_group=value) - self.assertRaises(ValueError, - self.manager.delete_endpoint_group_from_project, - project=value, - endpoint_group=uuid.uuid4().hex) diff --git a/keystoneclient/tests/unit/v3/test_endpoint_groups.py b/keystoneclient/tests/unit/v3/test_endpoint_groups.py deleted file mode 100644 index 364fd53c..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoint_groups.py +++ /dev/null @@ -1,34 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import endpoint_groups - - -class EndpointGroupTests(utils.ClientTestCase, utils.CrudTests): - - def setUp(self): - super(EndpointGroupTests, self).setUp() - self.key = 'endpoint_group' - self.collection_key = 'endpoint_groups' - self.model = endpoint_groups.EndpointGroup - self.manager = self.client.endpoint_groups - self.path_prefix = 'OS-EP-FILTER' - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('filters', '{"interface": "public"}') - kwargs.setdefault('description', uuid.uuid4().hex) - return kwargs diff --git a/keystoneclient/tests/unit/v3/test_endpoint_policy.py b/keystoneclient/tests/unit/v3/test_endpoint_policy.py deleted file mode 100644 index 69d90ae5..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoint_policy.py +++ /dev/null @@ -1,242 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import test_endpoint_filter -from keystoneclient.tests.unit.v3 import utils - - -class EndpointPolicyTests(utils.ClientTestCase, - test_endpoint_filter.EndpointTestUtils): - """Test policy-endpoint associations (a.k.a. EndpointPolicy Extension).""" - - def setUp(self): - super(EndpointPolicyTests, self).setUp() - self.manager = self.client.endpoint_policy - - def new_policy_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('blob', uuid.uuid4().hex) - return kwargs - - def new_region_ref(self, **kwargs): - kwargs = self.new_ref(**kwargs) - return kwargs - - def new_service_ref(self, **kwargs): - kwargs = self.new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - return kwargs - - def _crud_policy_association_for_endpoint_via_id( - self, http_action, manager_action): - policy_id = uuid.uuid4().hex - endpoint_id = uuid.uuid4().hex - - self.stub_url(http_action, - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'endpoints', endpoint_id], - status_code=204) - manager_action(policy=policy_id, endpoint=endpoint_id) - - def _crud_policy_association_for_endpoint_via_obj( - self, http_action, manager_action): - policy_ref = self.new_policy_ref() - endpoint_ref = self.new_endpoint_ref() - policy = self.client.policies.resource_class( - self.client.policies, policy_ref, loaded=True) - endpoint = self.client.endpoints.resource_class( - self.client.endpoints, endpoint_ref, loaded=True) - - self.stub_url(http_action, - ['policies', policy_ref['id'], - self.manager.OS_EP_POLICY_EXT, - 'endpoints', endpoint_ref['id']], - status_code=204) - manager_action(policy=policy, endpoint=endpoint) - - def test_create_policy_association_for_endpoint_via_id(self): - self._crud_policy_association_for_endpoint_via_id( - 'PUT', self.manager.create_policy_association_for_endpoint) - - def test_create_policy_association_for_endpoint_via_obj(self): - self._crud_policy_association_for_endpoint_via_obj( - 'PUT', self.manager.create_policy_association_for_endpoint) - - def test_check_policy_association_for_endpoint_via_id(self): - self._crud_policy_association_for_endpoint_via_id( - 'HEAD', self.manager.check_policy_association_for_endpoint) - - def test_check_policy_association_for_endpoint_via_obj(self): - self._crud_policy_association_for_endpoint_via_obj( - 'HEAD', self.manager.check_policy_association_for_endpoint) - - def test_delete_policy_association_for_endpoint_via_id(self): - self._crud_policy_association_for_endpoint_via_id( - 'DELETE', self.manager.delete_policy_association_for_endpoint) - - def test_delete_policy_association_for_endpoint_via_obj(self): - self._crud_policy_association_for_endpoint_via_obj( - 'DELETE', self.manager.delete_policy_association_for_endpoint) - - def _crud_policy_association_for_service_via_id( - self, http_action, manager_action): - policy_id = uuid.uuid4().hex - service_id = uuid.uuid4().hex - - self.stub_url(http_action, - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'services', service_id], - status_code=204) - manager_action(policy=policy_id, service=service_id) - - def _crud_policy_association_for_service_via_obj( - self, http_action, manager_action): - policy_ref = self.new_policy_ref() - service_ref = self.new_service_ref() - policy = self.client.policies.resource_class( - self.client.policies, policy_ref, loaded=True) - service = self.client.services.resource_class( - self.client.services, service_ref, loaded=True) - - self.stub_url(http_action, - ['policies', policy_ref['id'], - self.manager.OS_EP_POLICY_EXT, - 'services', service_ref['id']], - status_code=204) - manager_action(policy=policy, service=service) - - def test_create_policy_association_for_service_via_id(self): - self._crud_policy_association_for_service_via_id( - 'PUT', self.manager.create_policy_association_for_service) - - def test_create_policy_association_for_service_via_obj(self): - self._crud_policy_association_for_service_via_obj( - 'PUT', self.manager.create_policy_association_for_service) - - def test_check_policy_association_for_service_via_id(self): - self._crud_policy_association_for_service_via_id( - 'HEAD', self.manager.check_policy_association_for_service) - - def test_check_policy_association_for_service_via_obj(self): - self._crud_policy_association_for_service_via_obj( - 'HEAD', self.manager.check_policy_association_for_service) - - def test_delete_policy_association_for_service_via_id(self): - self._crud_policy_association_for_service_via_id( - 'DELETE', self.manager.delete_policy_association_for_service) - - def test_delete_policy_association_for_service_via_obj(self): - self._crud_policy_association_for_service_via_obj( - 'DELETE', self.manager.delete_policy_association_for_service) - - def _crud_policy_association_for_region_and_service_via_id( - self, http_action, manager_action): - policy_id = uuid.uuid4().hex - region_id = uuid.uuid4().hex - service_id = uuid.uuid4().hex - - self.stub_url(http_action, - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'services', service_id, 'regions', region_id], - status_code=204) - manager_action(policy=policy_id, region=region_id, service=service_id) - - def _crud_policy_association_for_region_and_service_via_obj( - self, http_action, manager_action): - policy_ref = self.new_policy_ref() - region_ref = self.new_region_ref() - service_ref = self.new_service_ref() - policy = self.client.policies.resource_class( - self.client.policies, policy_ref, loaded=True) - region = self.client.regions.resource_class( - self.client.regions, region_ref, loaded=True) - service = self.client.services.resource_class( - self.client.services, service_ref, loaded=True) - - self.stub_url(http_action, - ['policies', policy_ref['id'], - self.manager.OS_EP_POLICY_EXT, - 'services', service_ref['id'], - 'regions', region_ref['id']], - status_code=204) - manager_action(policy=policy, region=region, service=service) - - def test_create_policy_association_for_region_and_service_via_id(self): - self._crud_policy_association_for_region_and_service_via_id( - 'PUT', - self.manager.create_policy_association_for_region_and_service) - - def test_create_policy_association_for_region_and_service_via_obj(self): - self._crud_policy_association_for_region_and_service_via_obj( - 'PUT', - self.manager.create_policy_association_for_region_and_service) - - def test_check_policy_association_for_region_and_service_via_id(self): - self._crud_policy_association_for_region_and_service_via_id( - 'HEAD', - self.manager.check_policy_association_for_region_and_service) - - def test_check_policy_association_for_region_and_service_via_obj(self): - self._crud_policy_association_for_region_and_service_via_obj( - 'HEAD', - self.manager.check_policy_association_for_region_and_service) - - def test_delete_policy_association_for_region_and_service_via_id(self): - self._crud_policy_association_for_region_and_service_via_id( - 'DELETE', - self.manager.delete_policy_association_for_region_and_service) - - def test_delete_policy_association_for_region_and_service_via_obj(self): - self._crud_policy_association_for_region_and_service_via_obj( - 'DELETE', - self.manager.delete_policy_association_for_region_and_service) - - def test_get_policy_for_endpoint(self): - endpoint_id = uuid.uuid4().hex - expected_policy = self.new_policy_ref() - - self.stub_url('GET', - ['endpoints', endpoint_id, self.manager.OS_EP_POLICY_EXT, - 'policy'], - json={'policy': expected_policy}, - status_code=200) - - policy_resp = self.manager.get_policy_for_endpoint( - endpoint=endpoint_id) - - self.assertEqual(expected_policy['id'], policy_resp.id) - self.assertEqual(expected_policy['blob'], policy_resp.blob) - self.assertEqual(expected_policy['type'], policy_resp.type) - - def test_list_endpoints_for_policy(self): - policy_id = uuid.uuid4().hex - endpoints = {'endpoints': [self.new_endpoint_ref(), - self.new_endpoint_ref()]} - self.stub_url('GET', - ['policies', policy_id, self.manager.OS_EP_POLICY_EXT, - 'endpoints'], - json=endpoints, - status_code=200) - - endpoints_resp = self.manager.list_endpoints_for_policy( - policy=policy_id) - - expected_endpoint_ids = [ - endpoint['id'] for endpoint in endpoints['endpoints']] - actual_endpoint_ids = [endpoint.id for endpoint in endpoints_resp] - self.assertEqual(expected_endpoint_ids, actual_endpoint_ids) diff --git a/keystoneclient/tests/unit/v3/test_endpoints.py b/keystoneclient/tests/unit/v3/test_endpoints.py deleted file mode 100644 index 40fc03be..00000000 --- a/keystoneclient/tests/unit/v3/test_endpoints.py +++ /dev/null @@ -1,104 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import endpoints - - -class EndpointTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(EndpointTests, self).setUp() - self.key = 'endpoint' - self.collection_key = 'endpoints' - self.model = endpoints.Endpoint - self.manager = self.client.endpoints - - def new_ref(self, **kwargs): - kwargs = super(EndpointTests, self).new_ref(**kwargs) - kwargs.setdefault('interface', 'public') - kwargs.setdefault('region', uuid.uuid4().hex) - kwargs.setdefault('service_id', uuid.uuid4().hex) - kwargs.setdefault('url', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def test_create_public_interface(self): - ref = self.new_ref(interface='public') - self.test_create(ref) - - def test_create_admin_interface(self): - ref = self.new_ref(interface='admin') - self.test_create(ref) - - def test_create_internal_interface(self): - ref = self.new_ref(interface='internal') - self.test_create(ref) - - def test_create_invalid_interface(self): - ref = self.new_ref(interface=uuid.uuid4().hex) - self.assertRaises(exceptions.ValidationError, self.manager.create, - **utils.parameterize(ref)) - - def test_update_public_interface(self): - ref = self.new_ref(interface='public') - self.test_update(ref) - - def test_update_admin_interface(self): - ref = self.new_ref(interface='admin') - self.test_update(ref) - - def test_update_internal_interface(self): - ref = self.new_ref(interface='internal') - self.test_update(ref) - - def test_update_invalid_interface(self): - ref = self.new_ref(interface=uuid.uuid4().hex) - ref['endpoint'] = "fake_endpoint" - self.assertRaises(exceptions.ValidationError, self.manager.update, - **utils.parameterize(ref)) - - def test_list_public_interface(self): - interface = 'public' - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.test_list(expected_path=expected_path, interface=interface) - - def test_list_admin_interface(self): - interface = 'admin' - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.test_list(expected_path=expected_path, interface=interface) - - def test_list_internal_interface(self): - interface = 'admin' - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.test_list(expected_path=expected_path, interface=interface) - - def test_list_invalid_interface(self): - interface = uuid.uuid4().hex - expected_path = 'v3/%s?interface=%s' % (self.collection_key, interface) - self.assertRaises(exceptions.ValidationError, self.manager.list, - expected_path=expected_path, interface=interface) - - def test_list_filtered_by_region(self): - region_id = uuid.uuid4().hex - ref_list = [self.new_ref(region=region_id), - self.new_ref(region=region_id)] - expected_path = 'v3/%s?region_id=%s' % (self.collection_key, region_id) - expected_query = {'region_id': region_id} - - # Validate passing either region or region_id result to the API call. - self.test_list(ref_list=ref_list, expected_path=expected_path, - expected_query=expected_query, region=region_id) - self.test_list(ref_list=ref_list, expected_path=expected_path, - expected_query=expected_query, region_id=region_id) diff --git a/keystoneclient/tests/unit/v3/test_federation.py b/keystoneclient/tests/unit/v3/test_federation.py deleted file mode 100644 index a760ed7d..00000000 --- a/keystoneclient/tests/unit/v3/test_federation.py +++ /dev/null @@ -1,584 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import uuid - -from keystoneauth1 import exceptions -from keystoneauth1 import fixture -from keystoneauth1.identity import v3 -from keystoneauth1 import session -from keystoneauth1.tests.unit import k2k_fixtures -import six -from testtools import matchers - -from keystoneclient import access -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import client -from keystoneclient.v3.contrib.federation import base -from keystoneclient.v3.contrib.federation import identity_providers -from keystoneclient.v3.contrib.federation import mappings -from keystoneclient.v3.contrib.federation import protocols -from keystoneclient.v3.contrib.federation import service_providers -from keystoneclient.v3 import domains -from keystoneclient.v3 import projects - - -class IdentityProviderTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(IdentityProviderTests, self).setUp() - self.key = 'identity_provider' - self.collection_key = 'identity_providers' - self.model = identity_providers.IdentityProvider - self.manager = self.client.federation.identity_providers - self.path_prefix = 'OS-FEDERATION' - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def test_positional_parameters_expect_fail(self): - """Ensure CrudManager raises TypeError exceptions. - - After passing wrong number of positional arguments - an exception should be raised. - - Operations to be tested: - * create() - * get() - * list() - * delete() - * update() - - """ - POS_PARAM_1 = uuid.uuid4().hex - POS_PARAM_2 = uuid.uuid4().hex - POS_PARAM_3 = uuid.uuid4().hex - - PARAMETERS = { - 'create': (POS_PARAM_1, POS_PARAM_2), - 'get': (POS_PARAM_1, POS_PARAM_2), - 'list': (POS_PARAM_1, POS_PARAM_2), - 'update': (POS_PARAM_1, POS_PARAM_2, POS_PARAM_3), - 'delete': (POS_PARAM_1, POS_PARAM_2) - } - - for f_name, args in PARAMETERS.items(): - self.assertRaises(TypeError, getattr(self.manager, f_name), - *args) - - def test_create(self): - ref = self.new_ref() - req_ref = ref.copy() - req_ref.pop('id') - - self.stub_entity('PUT', entity=ref, id=ref['id'], status_code=201) - - returned = self.manager.create(**ref) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - -class MappingTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(MappingTests, self).setUp() - self.key = 'mapping' - self.collection_key = 'mappings' - self.model = mappings.Mapping - self.manager = self.client.federation.mappings - self.path_prefix = 'OS-FEDERATION' - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('rules', [uuid.uuid4().hex, - uuid.uuid4().hex]) - return kwargs - - def test_create(self): - ref = self.new_ref() - manager_ref = ref.copy() - mapping_id = manager_ref.pop('id') - req_ref = ref.copy() - - self.stub_entity('PUT', entity=req_ref, id=mapping_id, - status_code=201) - - returned = self.manager.create(mapping_id=mapping_id, **manager_ref) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(manager_ref) - - -class ProtocolTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ProtocolTests, self).setUp() - self.key = 'protocol' - self.collection_key = 'protocols' - self.model = protocols.Protocol - self.manager = self.client.federation.protocols - self.path_prefix = 'OS-FEDERATION/identity_providers' - - def _transform_to_response(self, ref): - """Construct a response body from a dictionary.""" - response = copy.deepcopy(ref) - del response['identity_provider'] - return response - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('mapping_id', uuid.uuid4().hex) - kwargs.setdefault('identity_provider', uuid.uuid4().hex) - return kwargs - - def build_parts(self, idp_id, protocol_id=None): - """Build array used to construct mocking URL. - - Construct and return array with URL parts later used - by methods like utils.TestCase.stub_entity(). - Example of URL: - ``OS-FEDERATION/identity_providers/{idp_id}/ - protocols/{protocol_id}`` - - """ - parts = ['OS-FEDERATION', 'identity_providers', - idp_id, 'protocols'] - if protocol_id: - parts.append(protocol_id) - return parts - - def test_build_url_provide_base_url(self): - base_url = uuid.uuid4().hex - parameters = {'base_url': base_url} - url = self.manager.build_url(dict_args_in_out=parameters) - self.assertEqual('/'.join([base_url, self.collection_key]), url) - - def test_build_url_w_idp_id(self): - """Test whether kwargs ``base_url`` discards object's base_url. - - This test shows, that when ``base_url`` is specified in the - dict_args_in_out dictionary, values like ``identity_provider_id`` - are not taken into consideration while building the url. - - """ - base_url, identity_provider_id = uuid.uuid4().hex, uuid.uuid4().hex - parameters = { - 'base_url': base_url, - 'identity_provider_id': identity_provider_id - } - url = self.manager.build_url(dict_args_in_out=parameters) - self.assertEqual('/'.join([base_url, self.collection_key]), url) - - def test_build_url_default_base_url(self): - identity_provider_id = uuid.uuid4().hex - parameters = { - 'identity_provider_id': identity_provider_id - } - - url = self.manager.build_url(dict_args_in_out=parameters) - self.assertEqual( - '/'.join([self.manager.base_url, identity_provider_id, - self.manager.collection_key]), url) - - def test_create(self): - """Test creating federation protocol tied to an Identity Provider. - - URL to be tested: PUT /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - expected = self._transform_to_response(ref) - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - self.stub_entity('PUT', entity=expected, - parts=parts, status_code=201) - returned = self.manager.create( - protocol_id=ref['id'], - identity_provider=ref['identity_provider'], - mapping=ref['mapping_id']) - self.assertEqual(expected, returned.to_dict()) - request_body = {'mapping_id': ref['mapping_id']} - self.assertEntityRequestBodyIs(request_body) - - def test_get(self): - """Fetch federation protocol object. - - URL to be tested: GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - expected = self._transform_to_response(ref) - - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - self.stub_entity('GET', entity=expected, - parts=parts, status_code=201) - - returned = self.manager.get(ref['identity_provider'], - ref['id']) - self.assertIsInstance(returned, self.model) - self.assertEqual(expected, returned.to_dict()) - - def test_delete(self): - """Delete federation protocol object. - - URL to be tested: DELETE /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - - self.stub_entity('DELETE', parts=parts, status_code=204) - - self.manager.delete(ref['identity_provider'], - ref['id']) - - def test_list(self): - """Test listing all federation protocols tied to the Identity Provider. - - URL to be tested: GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols - - """ - def _ref_protocols(): - return { - 'id': uuid.uuid4().hex, - 'mapping_id': uuid.uuid4().hex - } - - ref = self.new_ref() - expected = [_ref_protocols() for _ in range(3)] - parts = self.build_parts(idp_id=ref['identity_provider']) - self.stub_entity('GET', parts=parts, - entity=expected, status_code=200) - - returned = self.manager.list(ref['identity_provider']) - for obj, ref_obj in zip(returned, expected): - self.assertEqual(obj.to_dict(), ref_obj) - - def test_list_by_id(self): - # The test in the parent class needs to be overridden because it - # assumes globally unique IDs, which is not the case with protocol IDs - # (which are contextualized per identity provider). - ref = self.new_ref() - super(ProtocolTests, self).test_list_by_id( - ref=ref, - identity_provider=ref['identity_provider'], - id=ref['id']) - - def test_list_params(self): - request_args = self.new_ref() - filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} - parts = self.build_parts(request_args['identity_provider']) - - # Return HTTP 401 as we don't accept such requests. - self.stub_entity('GET', parts=parts, status_code=401) - self.assertRaises(exceptions.Unauthorized, - self.manager.list, - request_args['identity_provider'], - **filter_kwargs) - self.assertQueryStringContains(**filter_kwargs) - - def test_update(self): - """Test updating federation protocol. - - URL to be tested: PATCH /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - """ - ref = self.new_ref() - expected = self._transform_to_response(ref) - - parts = self.build_parts( - idp_id=ref['identity_provider'], - protocol_id=ref['id']) - - self.stub_entity('PATCH', parts=parts, - entity=expected, status_code=200) - - returned = self.manager.update(ref['identity_provider'], - ref['id'], - mapping=ref['mapping_id']) - self.assertIsInstance(returned, self.model) - self.assertEqual(expected, returned.to_dict()) - request_body = {'mapping_id': ref['mapping_id']} - self.assertEntityRequestBodyIs(request_body) - - -class EntityManagerTests(utils.ClientTestCase): - def test_create_object_expect_fail(self): - self.assertRaises(TypeError, - base.EntityManager, - self.client) - - -class FederationProjectTests(utils.ClientTestCase): - - def setUp(self): - super(FederationProjectTests, self).setUp() - self.key = 'project' - self.collection_key = 'projects' - self.model = projects.Project - self.manager = self.client.federation.projects - self.URL = "%s%s" % (self.TEST_URL, '/auth/projects') - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_list_accessible_projects(self): - projects_ref = [self.new_ref(), self.new_ref()] - projects_json = { - self.collection_key: [self.new_ref(), self.new_ref()] - } - self.requests_mock.get(self.URL, json=projects_json) - returned_list = self.manager.list() - - self.assertEqual(len(projects_ref), len(returned_list)) - for project in returned_list: - self.assertIsInstance(project, self.model) - - -class K2KFederatedProjectTests(utils.TestCase): - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - TEST_PASS = 'password' - REQUEST_ECP_URL = TEST_URL + '/auth/OS-FEDERATION/saml2/ecp' - - SP_ID = 'sp1' - SP_ROOT_URL = 'https://example.com/v3' - SP_URL = 'https://example.com/Shibboleth.sso/SAML2/ECP' - SP_AUTH_URL = (SP_ROOT_URL + - '/OS-FEDERATION/identity_providers' - '/testidp/protocols/saml2/auth') - - def setUp(self): - super(K2KFederatedProjectTests, self).setUp() - self.token_v3 = fixture.V3Token() - self.token_v3.add_service_provider( - self.SP_ID, self.SP_AUTH_URL, self.SP_URL) - self.session = session.Session() - self.collection_key = 'projects' - self.model = projects.Project - self.URL = '%s%s' % (self.SP_ROOT_URL, '/auth/projects') - self.k2kplugin = self.get_plugin() - self._mock_k2k_flow_urls() - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def _get_base_plugin(self): - self.stub_url('POST', ['auth', 'tokens'], - headers={'X-Subject-Token': uuid.uuid4().hex}, - json=self.token_v3) - return v3.Password(self.TEST_URL, - username=self.TEST_USER, - password=self.TEST_PASS) - - def _mock_k2k_flow_urls(self): - # We need to check the auth versions available - self.requests_mock.get( - self.TEST_URL, - json={'version': fixture.V3Discovery(self.TEST_URL)}, - headers={'Content-Type': 'application/json'}) - - # The identity provider receives a request for an ECP wrapped - # assertion. This assertion contains the user authentication info - # and will be presented to the service provider - self.requests_mock.register_uri( - 'POST', - self.REQUEST_ECP_URL, - content=six.b(k2k_fixtures.ECP_ENVELOPE), - headers={'Content-Type': 'application/vnd.paos+xml'}, - status_code=200) - - # The service provider is presented with the ECP wrapped assertion - # generated by the identity provider and should return a redirect - # (302 or 303) upon successful authentication - self.requests_mock.register_uri( - 'POST', - self.SP_URL, - content=six.b(k2k_fixtures.TOKEN_BASED_ECP), - headers={'Content-Type': 'application/vnd.paos+xml'}, - status_code=302) - - # Should not follow the redirect URL, but use the auth_url attribute - self.requests_mock.register_uri( - 'GET', - self.SP_AUTH_URL, - json=k2k_fixtures.UNSCOPED_TOKEN, - headers={'X-Subject-Token': k2k_fixtures.UNSCOPED_TOKEN_HEADER}) - - def get_plugin(self, **kwargs): - kwargs.setdefault('base_plugin', self._get_base_plugin()) - kwargs.setdefault('service_provider', self.SP_ID) - return v3.Keystone2Keystone(**kwargs) - - def test_list_projects(self): - k2k_client = client.Client(session=self.session, auth=self.k2kplugin) - self.requests_mock.get(self.URL, json={ - self.collection_key: [self.new_ref(), self.new_ref()] - }) - self.requests_mock.get(self.SP_ROOT_URL, json={ - 'version': fixture.discovery.V3Discovery(self.SP_ROOT_URL) - }) - returned_list = k2k_client.federation.projects.list() - - self.assertThat(returned_list, matchers.HasLength(2)) - for project in returned_list: - self.assertIsInstance(project, self.model) - - -class FederationDomainTests(utils.ClientTestCase): - - def setUp(self): - super(FederationDomainTests, self).setUp() - self.key = 'domain' - self.collection_key = 'domains' - self.model = domains.Domain - self.manager = self.client.federation.domains - - self.URL = "%s%s" % (self.TEST_URL, '/auth/domains') - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - return kwargs - - def test_list_accessible_domains(self): - domains_ref = [self.new_ref(), self.new_ref()] - domains_json = { - self.collection_key: domains_ref - } - self.requests_mock.get(self.URL, json=domains_json) - returned_list = self.manager.list() - self.assertEqual(len(domains_ref), len(returned_list)) - for domain in returned_list: - self.assertIsInstance(domain, self.model) - - -class FederatedTokenTests(utils.ClientTestCase): - - def setUp(self): - super(FederatedTokenTests, self).setUp() - token = fixture.V3FederationToken() - token.set_project_scope() - token.add_role() - self.federated_token = access.AccessInfo.factory(body=token) - - def test_federated_property_federated_token(self): - """Check if is_federated property returns expected value.""" - self.assertTrue(self.federated_token.is_federated) - - def test_get_user_domain_name(self): - """Ensure a federated user's domain name does not exist.""" - self.assertIsNone(self.federated_token.user_domain_name) - - def test_get_user_domain_id(self): - """Ensure a federated user's domain ID does not exist.""" - self.assertEqual('Federated', self.federated_token.user_domain_id) - - -class ServiceProviderTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ServiceProviderTests, self).setUp() - self.key = 'service_provider' - self.collection_key = 'service_providers' - self.model = service_providers.ServiceProvider - self.manager = self.client.federation.service_providers - self.path_prefix = 'OS-FEDERATION' - - def new_ref(self, **kwargs): - kwargs.setdefault('auth_url', uuid.uuid4().hex) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault('sp_url', uuid.uuid4().hex) - return kwargs - - def test_positional_parameters_expect_fail(self): - """Ensure CrudManager raises TypeError exceptions. - - After passing wrong number of positional arguments - an exception should be raised. - - Operations to be tested: - * create() - * get() - * list() - * delete() - * update() - - """ - POS_PARAM_1 = uuid.uuid4().hex - POS_PARAM_2 = uuid.uuid4().hex - POS_PARAM_3 = uuid.uuid4().hex - - PARAMETERS = { - 'create': (POS_PARAM_1, POS_PARAM_2), - 'get': (POS_PARAM_1, POS_PARAM_2), - 'list': (POS_PARAM_1, POS_PARAM_2), - 'update': (POS_PARAM_1, POS_PARAM_2, POS_PARAM_3), - 'delete': (POS_PARAM_1, POS_PARAM_2) - } - - for f_name, args in PARAMETERS.items(): - self.assertRaises(TypeError, getattr(self.manager, f_name), - *args) - - def test_create(self): - ref = self.new_ref() - - # req_ref argument allows you to specify a different - # signature for the request when the manager does some - # conversion before doing the request (e.g. converting - # from datetime object to timestamp string) - req_ref = ref.copy() - req_ref.pop('id') - - self.stub_entity('PUT', entity=ref, id=ref['id'], status_code=201) - - returned = self.manager.create(**ref) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) diff --git a/keystoneclient/tests/unit/v3/test_groups.py b/keystoneclient/tests/unit/v3/test_groups.py deleted file mode 100644 index 90fff0e6..00000000 --- a/keystoneclient/tests/unit/v3/test_groups.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import groups - - -class GroupTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(GroupTests, self).setUp() - self.key = 'group' - self.collection_key = 'groups' - self.model = groups.Group - self.manager = self.client.groups - - def new_ref(self, **kwargs): - kwargs = super(GroupTests, self).new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_list_groups_for_user(self): - user_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['users', user_id, self.collection_key], - status_code=200, entity=ref_list) - - returned_list = self.manager.list(user=user_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_list_groups_for_domain(self): - ref_list = [self.new_ref(), self.new_ref()] - domain_id = uuid.uuid4().hex - - self.stub_entity('GET', - [self.collection_key], - status_code=200, entity=ref_list) - - returned_list = self.manager.list(domain=domain_id) - self.assertTrue(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - self.assertQueryStringIs('domain_id=%s' % domain_id) diff --git a/keystoneclient/tests/unit/v3/test_oauth1.py b/keystoneclient/tests/unit/v3/test_oauth1.py deleted file mode 100644 index f939244d..00000000 --- a/keystoneclient/tests/unit/v3/test_oauth1.py +++ /dev/null @@ -1,290 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import uuid - -import mock -import six -from six.moves.urllib import parse as urlparse -from testtools import matchers - -from keystoneclient import session -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils -from keystoneclient import utils as client_utils -from keystoneclient.v3.contrib.oauth1 import access_tokens -from keystoneclient.v3.contrib.oauth1 import auth -from keystoneclient.v3.contrib.oauth1 import consumers -from keystoneclient.v3.contrib.oauth1 import request_tokens - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class ConsumerTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - if oauth1 is None: - self.skipTest('oauthlib package not available') - - super(ConsumerTests, self).setUp() - self.key = 'consumer' - self.collection_key = 'consumers' - self.model = consumers.Consumer - self.manager = self.client.oauth1.consumers - self.path_prefix = 'OS-OAUTH1' - - def new_ref(self, **kwargs): - kwargs = super(ConsumerTests, self).new_ref(**kwargs) - kwargs.setdefault('description', uuid.uuid4().hex) - return kwargs - - def test_description_is_optional(self): - consumer_id = uuid.uuid4().hex - resp_ref = {'consumer': {'description': None, - 'id': consumer_id}} - - self.stub_url('POST', - [self.path_prefix, self.collection_key], - status_code=201, json=resp_ref) - - consumer = self.manager.create() - self.assertEqual(consumer_id, consumer.id) - self.assertIsNone(consumer.description) - - def test_description_not_included(self): - consumer_id = uuid.uuid4().hex - resp_ref = {'consumer': {'id': consumer_id}} - - self.stub_url('POST', - [self.path_prefix, self.collection_key], - status_code=201, json=resp_ref) - - consumer = self.manager.create() - self.assertEqual(consumer_id, consumer.id) - - -class TokenTests(object): - def _new_oauth_token(self): - key = uuid.uuid4().hex - secret = uuid.uuid4().hex - params = {'oauth_token': key, 'oauth_token_secret': secret} - token = urlparse.urlencode(params) - return (key, secret, token) - - def _new_oauth_token_with_expires_at(self): - key, secret, token = self._new_oauth_token() - expires_at = client_utils.strtime() - params = {'oauth_token': key, - 'oauth_token_secret': secret, - 'oauth_expires_at': expires_at} - token = urlparse.urlencode(params) - return (key, secret, expires_at, token) - - def _validate_oauth_headers(self, auth_header, oauth_client): - """Validate data in the headers. - - Assert that the data in the headers matches the data - that is produced from oauthlib. - """ - self.assertThat(auth_header, matchers.StartsWith('OAuth ')) - parameters = dict( - oauth1.rfc5849.utils.parse_authorization_header(auth_header)) - - self.assertEqual('HMAC-SHA1', parameters['oauth_signature_method']) - self.assertEqual('1.0', parameters['oauth_version']) - self.assertIsInstance(parameters['oauth_nonce'], six.string_types) - self.assertEqual(oauth_client.client_key, - parameters['oauth_consumer_key']) - if oauth_client.resource_owner_key: - self.assertEqual(oauth_client.resource_owner_key, - parameters['oauth_token'],) - if oauth_client.verifier: - self.assertEqual(oauth_client.verifier, - parameters['oauth_verifier']) - if oauth_client.callback_uri: - self.assertEqual(oauth_client.callback_uri, - parameters['oauth_callback']) - return parameters - - -class RequestTokenTests(utils.ClientTestCase, TokenTests): - def setUp(self): - if oauth1 is None: - self.skipTest('oauthlib package not available') - - super(RequestTokenTests, self).setUp() - self.model = request_tokens.RequestToken - self.manager = self.client.oauth1.request_tokens - self.path_prefix = 'OS-OAUTH1' - - def test_authorize_request_token(self): - request_key = uuid.uuid4().hex - info = {'id': request_key, - 'key': request_key, - 'secret': uuid.uuid4().hex} - request_token = request_tokens.RequestToken(self.manager, info) - - verifier = uuid.uuid4().hex - resp_ref = {'token': {'oauth_verifier': verifier}} - self.stub_url('PUT', - [self.path_prefix, 'authorize', request_key], - status_code=200, json=resp_ref) - - # Assert the manager is returning the expected data - role_id = uuid.uuid4().hex - token = request_token.authorize([role_id]) - self.assertEqual(verifier, token.oauth_verifier) - - # Assert that the request was sent in the expected structure - exp_body = {'roles': [{'id': role_id}]} - self.assertRequestBodyIs(json=exp_body) - - def test_create_request_token(self): - project_id = uuid.uuid4().hex - consumer_key = uuid.uuid4().hex - consumer_secret = uuid.uuid4().hex - - request_key, request_secret, resp_ref = self._new_oauth_token() - - headers = {'Content-Type': 'application/x-www-form-urlencoded'} - self.stub_url('POST', [self.path_prefix, 'request_token'], - status_code=201, text=resp_ref, headers=headers) - - # Assert the manager is returning request token object - request_token = self.manager.create(consumer_key, consumer_secret, - project_id) - self.assertIsInstance(request_token, self.model) - self.assertEqual(request_key, request_token.key) - self.assertEqual(request_secret, request_token.secret) - - # Assert that the project id is in the header - self.assertRequestHeaderEqual('requested-project-id', project_id) - req_headers = self.requests_mock.last_request.headers - - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - signature_method=oauth1.SIGNATURE_HMAC, - callback_uri="oob") - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - - -class AccessTokenTests(utils.ClientTestCase, TokenTests): - def setUp(self): - if oauth1 is None: - self.skipTest('oauthlib package not available') - - super(AccessTokenTests, self).setUp() - self.manager = self.client.oauth1.access_tokens - self.model = access_tokens.AccessToken - self.path_prefix = 'OS-OAUTH1' - - def test_create_access_token_expires_at(self): - verifier = uuid.uuid4().hex - consumer_key = uuid.uuid4().hex - consumer_secret = uuid.uuid4().hex - request_key = uuid.uuid4().hex - request_secret = uuid.uuid4().hex - - t = self._new_oauth_token_with_expires_at() - access_key, access_secret, expires_at, resp_ref = t - - headers = {'Content-Type': 'application/x-www-form-urlencoded'} - self.stub_url('POST', [self.path_prefix, 'access_token'], - status_code=201, text=resp_ref, headers=headers) - - # Assert that the manager creates an access token object - access_token = self.manager.create(consumer_key, consumer_secret, - request_key, request_secret, - verifier) - self.assertIsInstance(access_token, self.model) - self.assertEqual(access_key, access_token.key) - self.assertEqual(access_secret, access_token.secret) - self.assertEqual(expires_at, access_token.expires) - - req_headers = self.requests_mock.last_request.headers - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - resource_owner_key=request_key, - resource_owner_secret=request_secret, - signature_method=oauth1.SIGNATURE_HMAC, - verifier=verifier) - - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - - -class AuthenticateWithOAuthTests(utils.TestCase, TokenTests): - def setUp(self): - super(AuthenticateWithOAuthTests, self).setUp() - if oauth1 is None: - self.skipTest('optional package oauthlib is not installed') - - def test_oauth_authenticate_success(self): - consumer_key = uuid.uuid4().hex - consumer_secret = uuid.uuid4().hex - access_key = uuid.uuid4().hex - access_secret = uuid.uuid4().hex - - # Just use an existing project scoped token and change - # the methods to oauth1, and add an OS-OAUTH1 section. - oauth_token = client_fixtures.project_scoped_token() - oauth_token['methods'] = ["oauth1"] - oauth_token['OS-OAUTH1'] = {"consumer_id": consumer_key, - "access_token_id": access_key} - self.stub_auth(json=oauth_token) - - with self.deprecations.expect_deprecations_here(): - a = auth.OAuth(self.TEST_URL, consumer_key=consumer_key, - consumer_secret=consumer_secret, - access_key=access_key, - access_secret=access_secret) - s = session.Session(auth=a) - t = s.get_token() - self.assertEqual(self.TEST_TOKEN, t) - - OAUTH_REQUEST_BODY = { - "auth": { - "identity": { - "methods": ["oauth1"], - "oauth1": {} - } - } - } - - self.assertRequestBodyIs(json=OAUTH_REQUEST_BODY) - - # Assert that the headers have the same oauthlib data - req_headers = self.requests_mock.last_request.headers - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - resource_owner_key=access_key, - resource_owner_secret=access_secret, - signature_method=oauth1.SIGNATURE_HMAC) - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - - -class TestOAuthLibModule(utils.TestCase): - - def test_no_oauthlib_installed(self): - with mock.patch.object(auth, 'oauth1', None): - self.assertRaises(NotImplementedError, - auth.OAuth, - self.TEST_URL, - consumer_key=uuid.uuid4().hex, - consumer_secret=uuid.uuid4().hex, - access_key=uuid.uuid4().hex, - access_secret=uuid.uuid4().hex) diff --git a/keystoneclient/tests/unit/v3/test_policies.py b/keystoneclient/tests/unit/v3/test_policies.py deleted file mode 100644 index 47be4838..00000000 --- a/keystoneclient/tests/unit/v3/test_policies.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import policies - - -class PolicyTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(PolicyTests, self).setUp() - self.key = 'policy' - self.collection_key = 'policies' - self.model = policies.Policy - self.manager = self.client.policies - - def new_ref(self, **kwargs): - kwargs = super(PolicyTests, self).new_ref(**kwargs) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('blob', uuid.uuid4().hex) - return kwargs diff --git a/keystoneclient/tests/unit/v3/test_projects.py b/keystoneclient/tests/unit/v3/test_projects.py deleted file mode 100644 index 48477ed4..00000000 --- a/keystoneclient/tests/unit/v3/test_projects.py +++ /dev/null @@ -1,314 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1 import exceptions as ksa_exceptions - -from keystoneclient import exceptions as ksc_exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import projects - - -class ProjectTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ProjectTests, self).setUp() - self.key = 'project' - self.collection_key = 'projects' - self.model = projects.Project - self.manager = self.client.projects - - def new_ref(self, **kwargs): - kwargs = super(ProjectTests, self).new_ref(**kwargs) - return self._new_project_ref(ref=kwargs) - - def _new_project_ref(self, ref=None): - ref = ref or {} - ref.setdefault('domain_id', uuid.uuid4().hex) - ref.setdefault('enabled', True) - ref.setdefault('name', uuid.uuid4().hex) - return ref - - def test_list_projects_for_user(self): - ref_list = [self.new_ref(), self.new_ref()] - user_id = uuid.uuid4().hex - - self.stub_entity('GET', - ['users', user_id, self.collection_key], - entity=ref_list) - - returned_list = self.manager.list(user=user_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_list_projects_for_domain(self): - ref_list = [self.new_ref(), self.new_ref()] - domain_id = uuid.uuid4().hex - - self.stub_entity('GET', [self.collection_key], - entity=ref_list) - - returned_list = self.manager.list(domain=domain_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - self.assertQueryStringIs('domain_id=%s' % domain_id) - - def test_create_with_parent(self): - parent_ref = self.new_ref() - parent_ref['parent_id'] = uuid.uuid4().hex - parent = self.test_create(ref=parent_ref) - parent.id = parent_ref['id'] - - # Create another project under 'parent' in the hierarchy - ref = self.new_ref() - ref['parent_id'] = parent.id - - child_ref = ref.copy() - del child_ref['parent_id'] - child_ref['parent'] = parent - - # test_create() pops the 'id' of the mocked response - del ref['id'] - - # Resource objects may peform lazy-loading. The create() method of - # ProjectManager will try to access the 'uuid' attribute of the parent - # object, which will trigger a call to fetch the Resource attributes. - self.stub_entity('GET', id=parent_ref['id'], entity=parent_ref) - self.test_create(ref=child_ref, req_ref=ref) - - def test_create_with_parent_id(self): - ref = self._new_project_ref() - ref['parent_id'] = uuid.uuid4().hex - - self.stub_entity('POST', entity=ref, status_code=201) - - returned = self.manager.create(name=ref['name'], - domain=ref['domain_id'], - parent_id=ref['parent_id']) - - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(ref) - - def test_create_with_parent_and_parent_id(self): - ref = self._new_project_ref() - ref['parent_id'] = uuid.uuid4().hex - - self.stub_entity('POST', entity=ref, status_code=201) - - # Should ignore the 'parent_id' argument since we are also passing - # 'parent' - returned = self.manager.create(name=ref['name'], - domain=ref['domain_id'], - parent=ref['parent_id'], - parent_id=uuid.uuid4().hex) - - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(ref) - - def _create_projects_hierarchy(self, hierarchy_size=3): - """Create a project hierarchy with specified size. - - :param hierarchy_size: the desired hierarchy size, default is 3. - - :returns: a list of the projects in the created hierarchy. - - """ - ref = self.new_ref() - project_id = ref['id'] - projects = [ref] - - for i in range(1, hierarchy_size): - new_ref = self.new_ref() - new_ref['parent_id'] = project_id - projects.append(new_ref) - project_id = new_ref['id'] - - return projects - - def test_get_with_subtree_as_ids(self): - projects = self._create_projects_hierarchy() - ref = projects[0] - - # We will query for projects[0] subtree, it should include projects[1] - # and projects[2] structured like the following: - # { - # projects[1]: { - # projects[2]: None - # } - # } - ref['subtree'] = { - projects[1]['id']: { - projects[2]['id']: None - } - } - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], subtree_as_ids=True) - self.assertQueryStringIs('subtree_as_ids') - self.assertEqual(ref['subtree'], returned.subtree) - - def test_get_with_parents_as_ids(self): - projects = self._create_projects_hierarchy() - ref = projects[2] - - # We will query for projects[2] parents, it should include projects[1] - # and projects[0] structured like the following: - # { - # projects[1]: { - # projects[0]: None - # } - # } - ref['parents'] = { - projects[1]['id']: { - projects[0]['id']: None - } - } - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], parents_as_ids=True) - self.assertQueryStringIs('parents_as_ids') - self.assertEqual(ref['parents'], returned.parents) - - def test_get_with_parents_as_ids_and_subtree_as_ids(self): - ref = self.new_ref() - projects = self._create_projects_hierarchy() - ref = projects[1] - - # We will query for projects[1] subtree and parents. The subtree should - # include projects[2] and the parents should include projects[2]. - ref['parents'] = { - projects[0]['id']: None - } - ref['subtree'] = { - projects[2]['id']: None - } - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], - parents_as_ids=True, - subtree_as_ids=True) - self.assertQueryStringIs('subtree_as_ids&parents_as_ids') - self.assertEqual(ref['parents'], returned.parents) - self.assertEqual(ref['subtree'], returned.subtree) - - def test_get_with_subtree_as_list(self): - projects = self._create_projects_hierarchy() - ref = projects[0] - - ref['subtree_as_list'] = [] - for i in range(1, len(projects)): - ref['subtree_as_list'].append(projects[i]) - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], subtree_as_list=True) - self.assertQueryStringIs('subtree_as_list') - for i in range(1, len(projects)): - for attr in projects[i]: - child = getattr(returned, 'subtree_as_list')[i - 1] - self.assertEqual( - child[attr], - projects[i][attr], - 'Expected different %s' % attr) - - def test_get_with_parents_as_list(self): - projects = self._create_projects_hierarchy() - ref = projects[2] - - ref['parents_as_list'] = [] - for i in range(0, len(projects) - 1): - ref['parents_as_list'].append(projects[i]) - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], parents_as_list=True) - self.assertQueryStringIs('parents_as_list') - for i in range(0, len(projects) - 1): - for attr in projects[i]: - parent = getattr(returned, 'parents_as_list')[i] - self.assertEqual( - parent[attr], - projects[i][attr], - 'Expected different %s' % attr) - - def test_get_with_parents_as_list_and_subtree_as_list(self): - ref = self.new_ref() - projects = self._create_projects_hierarchy() - ref = projects[1] - - ref['parents_as_list'] = [projects[0]] - ref['subtree_as_list'] = [projects[2]] - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id'], - parents_as_list=True, - subtree_as_list=True) - self.assertQueryStringIs('subtree_as_list&parents_as_list') - - for attr in projects[0]: - parent = getattr(returned, 'parents_as_list')[0] - self.assertEqual( - parent[attr], - projects[0][attr], - 'Expected different %s' % attr) - - for attr in projects[2]: - child = getattr(returned, 'subtree_as_list')[0] - self.assertEqual( - child[attr], - projects[2][attr], - 'Expected different %s' % attr) - - def test_get_with_invalid_parameters_combination(self): - # subtree_as_list and subtree_as_ids can not be included at the - # same time in the call. - self.assertRaises(ksc_exceptions.ValidationError, - self.manager.get, - project=uuid.uuid4().hex, - subtree_as_list=True, - subtree_as_ids=True) - - # parents_as_list and parents_as_ids can not be included at the - # same time in the call. - self.assertRaises(ksc_exceptions.ValidationError, - self.manager.get, - project=uuid.uuid4().hex, - parents_as_list=True, - parents_as_ids=True) - - def test_update_with_parent_project(self): - ref = self.new_ref() - ref['parent_id'] = uuid.uuid4().hex - - self.stub_entity('PATCH', id=ref['id'], entity=ref, status_code=403) - req_ref = ref.copy() - req_ref.pop('id') - - # NOTE(rodrigods): this is the expected behaviour of the Identity - # server, a different implementation might not fail this request. - self.assertRaises(ksa_exceptions.Forbidden, self.manager.update, - ref['id'], **utils.parameterize(req_ref)) diff --git a/keystoneclient/tests/unit/v3/test_regions.py b/keystoneclient/tests/unit/v3/test_regions.py deleted file mode 100644 index 90ddfdc6..00000000 --- a/keystoneclient/tests/unit/v3/test_regions.py +++ /dev/null @@ -1,37 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import uuid - - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import regions - - -class RegionTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(RegionTests, self).setUp() - self.key = 'region' - self.collection_key = 'regions' - self.model = regions.Region - self.manager = self.client.regions - - def new_ref(self, **kwargs): - kwargs = super(RegionTests, self).new_ref(**kwargs) - kwargs.setdefault('enabled', True) - kwargs.setdefault('id', uuid.uuid4().hex) - return kwargs - - def test_update_enabled_defaults_to_none(self): - super(RegionTests, self).test_update( - req_ref={'description': uuid.uuid4().hex}) diff --git a/keystoneclient/tests/unit/v3/test_role_assignments.py b/keystoneclient/tests/unit/v3/test_role_assignments.py deleted file mode 100644 index b24799cb..00000000 --- a/keystoneclient/tests/unit/v3/test_role_assignments.py +++ /dev/null @@ -1,262 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import role_assignments - - -class RoleAssignmentsTests(utils.ClientTestCase, utils.CrudTests): - - def setUp(self): - super(RoleAssignmentsTests, self).setUp() - self.key = 'role_assignment' - self.collection_key = 'role_assignments' - self.model = role_assignments.RoleAssignment - self.manager = self.client.role_assignments - self.TEST_USER_DOMAIN_LIST = [{ - 'role': { - 'id': self.TEST_ROLE_ID - }, - 'scope': { - 'domain': { - 'id': self.TEST_DOMAIN_ID - } - }, - 'user': { - 'id': self.TEST_USER_ID - } - }] - self.TEST_GROUP_PROJECT_LIST = [{ - 'group': { - 'id': self.TEST_GROUP_ID - }, - 'role': { - 'id': self.TEST_ROLE_ID - }, - 'scope': { - 'project': { - 'id': self.TEST_TENANT_ID - } - } - }] - self.TEST_USER_PROJECT_LIST = [{ - 'user': { - 'id': self.TEST_USER_ID - }, - 'role': { - 'id': self.TEST_ROLE_ID - }, - 'scope': { - 'project': { - 'id': self.TEST_TENANT_ID - } - } - }] - - self.TEST_ALL_RESPONSE_LIST = (self.TEST_USER_PROJECT_LIST + - self.TEST_GROUP_PROJECT_LIST + - self.TEST_USER_DOMAIN_LIST) - - def _assert_returned_list(self, ref_list, returned_list): - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_list_by_id(self): - # It doesn't make sense to "list role assignments by ID" at all, given - # that they don't have globally unique IDs in the first place. But - # calling RoleAssignmentsManager.list(id=...) should still raise a - # TypeError when given an unexpected keyword argument 'id', so we don't - # actually have to modify the test in the superclass... I just wanted - # to make a note here in case the superclass changes. - super(RoleAssignmentsTests, self).test_list_by_id() - - def test_list_params(self): - ref_list = self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.project.id=%s&user.id=%s' % - (self.TEST_TENANT_ID, self.TEST_USER_ID)], - entity=ref_list) - - returned_list = self.manager.list(user=self.TEST_USER_ID, - project=self.TEST_TENANT_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.project.id': self.TEST_TENANT_ID, - 'user.id': self.TEST_USER_ID} - self.assertQueryStringContains(**kwargs) - - def test_all_assignments_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key], - entity=ref_list) - - returned_list = self.manager.list() - self._assert_returned_list(ref_list, returned_list) - - kwargs = {} - self.assertQueryStringContains(**kwargs) - - def test_project_assignments_list(self): - ref_list = self.TEST_GROUP_PROJECT_LIST + self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.project.id=%s' % self.TEST_TENANT_ID], - entity=ref_list) - - returned_list = self.manager.list(project=self.TEST_TENANT_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.project.id': self.TEST_TENANT_ID} - self.assertQueryStringContains(**kwargs) - - def test_project_assignments_list_include_subtree(self): - ref_list = self.TEST_GROUP_PROJECT_LIST + self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.project.id=%s&include_subtree=True' % - self.TEST_TENANT_ID], - entity=ref_list) - - returned_list = self.manager.list(project=self.TEST_TENANT_ID, - include_subtree=True) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.project.id': self.TEST_TENANT_ID, - 'include_subtree': 'True'} - self.assertQueryStringContains(**kwargs) - - def test_domain_assignments_list(self): - ref_list = self.TEST_USER_DOMAIN_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.domain.id=%s' % self.TEST_DOMAIN_ID], - entity=ref_list) - - returned_list = self.manager.list(domain=self.TEST_DOMAIN_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'scope.domain.id': self.TEST_DOMAIN_ID} - self.assertQueryStringContains(**kwargs) - - def test_group_assignments_list(self): - ref_list = self.TEST_GROUP_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?group.id=%s' % self.TEST_GROUP_ID], - entity=ref_list) - - returned_list = self.manager.list(group=self.TEST_GROUP_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'group.id': self.TEST_GROUP_ID} - self.assertQueryStringContains(**kwargs) - - def test_user_assignments_list(self): - ref_list = self.TEST_USER_DOMAIN_LIST + self.TEST_USER_PROJECT_LIST - self.stub_entity('GET', - [self.collection_key, - '?user.id=%s' % self.TEST_USER_ID], - entity=ref_list) - - returned_list = self.manager.list(user=self.TEST_USER_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'user.id': self.TEST_USER_ID} - self.assertQueryStringContains(**kwargs) - - def test_effective_assignments_list(self): - ref_list = self.TEST_USER_PROJECT_LIST + self.TEST_USER_DOMAIN_LIST - self.stub_entity('GET', - [self.collection_key, - '?effective=True'], - entity=ref_list) - - returned_list = self.manager.list(effective=True) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'effective': 'True'} - self.assertQueryStringContains(**kwargs) - - def test_include_names_assignments_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key, - '?include_names'], - entity=ref_list) - - returned_list = self.manager.list(include_names=True) - self._assert_returned_list(ref_list, returned_list) - kwargs = {'include_names': 'True'} - self.assertQueryStringContains(**kwargs) - - def test_role_assignments_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key, - '?role.id=' + self.TEST_ROLE_ID], - entity=ref_list) - - returned_list = self.manager.list(role=self.TEST_ROLE_ID) - self._assert_returned_list(ref_list, returned_list) - - kwargs = {'role.id': self.TEST_ROLE_ID} - self.assertQueryStringContains(**kwargs) - - def test_role_assignments_inherited_list(self): - ref_list = self.TEST_ALL_RESPONSE_LIST - self.stub_entity('GET', - [self.collection_key, - '?scope.OS-INHERIT:inherited_to=projects'], - entity=ref_list - ) - - returned_list = self.manager.list( - os_inherit_extension_inherited_to='projects') - self._assert_returned_list(ref_list, returned_list) - - query_string = 'scope.OS-INHERIT:inherited_to=projects' - self.assertQueryStringIs(query_string) - - def test_domain_and_project_list(self): - # Should only accept either domain or project, never both - self.assertRaises(exceptions.ValidationError, - self.manager.list, - domain=self.TEST_DOMAIN_ID, - project=self.TEST_TENANT_ID) - - def test_user_and_group_list(self): - # Should only accept either user or group, never both - self.assertRaises(exceptions.ValidationError, self.manager.list, - user=self.TEST_USER_ID, group=self.TEST_GROUP_ID) - - def test_create(self): - # Create not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.create) - - def test_update(self): - # Update not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.update) - - def test_delete(self): - # Delete not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.delete) - - def test_get(self): - # Get not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.get) - - def test_find(self): - # Find not supported for role assignments - self.assertRaises(exceptions.MethodNotImplemented, self.manager.find) diff --git a/keystoneclient/tests/unit/v3/test_roles.py b/keystoneclient/tests/unit/v3/test_roles.py deleted file mode 100644 index 51d9fc73..00000000 --- a/keystoneclient/tests/unit/v3/test_roles.py +++ /dev/null @@ -1,824 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import roles -from testtools import matchers - - -class RoleTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(RoleTests, self).setUp() - self.key = 'role' - self.collection_key = 'roles' - self.model = roles.Role - self.manager = self.client.roles - - def new_ref(self, **kwargs): - kwargs = super(RoleTests, self).new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def _new_domain_ref(self, **kwargs): - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - return kwargs - - def test_create_with_domain_id(self): - ref = self.new_ref() - ref['domain_id'] = uuid.uuid4().hex - self.test_create(ref=ref) - - def test_create_with_domain(self): - ref = self.new_ref() - domain_ref = self._new_domain_ref() - domain_ref['id'] = uuid.uuid4().hex - ref['domain_id'] = domain_ref['id'] - - self.stub_entity('POST', entity=ref, status_code=201) - returned = self.manager.create(name=ref['name'], - domain=domain_ref) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - - def test_domain_role_grant(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['domains', domain_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, user=user_id) - - def test_domain_role_grant_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'domains', domain_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, user=user_id, - os_inherit_extension_inherited=True) - - def test_project_role_grant_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'projects', project_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.grant(role=ref['id'], project=project_id, user=user_id, - os_inherit_extension_inherited=True) - - def test_domain_group_role_grant(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['domains', domain_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, group=group_id) - - def test_domain_group_role_grant_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'domains', domain_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=201) - - self.manager.grant(role=ref['id'], domain=domain_id, group=group_id, - os_inherit_extension_inherited=True) - - def test_project_group_role_grant_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['OS-INHERIT', 'projects', project_id, 'groups', - group_id, self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.grant(role=ref['id'], project=project_id, group=group_id, - os_inherit_extension_inherited=True) - - def test_domain_role_list(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['domains', domain_id, 'users', user_id, - self.collection_key], entity=ref_list) - - self.manager.list(domain=domain_id, user=user_id) - - def test_domain_role_list_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'domains', domain_id, 'users', user_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(domain=domain_id, user=user_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_project_user_role_list_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'projects', project_id, 'users', user_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(project=project_id, user=user_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_domain_group_role_list(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['domains', domain_id, 'groups', group_id, - self.collection_key], entity=ref_list) - - self.manager.list(domain=domain_id, group=group_id) - - def test_domain_group_role_list_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'domains', domain_id, 'groups', group_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(domain=domain_id, group=group_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_project_group_role_list_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['OS-INHERIT', - 'projects', project_id, 'groups', group_id, - self.collection_key, 'inherited_to_projects'], - entity=ref_list) - - returned_list = self.manager.list(project=project_id, group=group_id, - os_inherit_extension_inherited=True) - - self.assertThat(ref_list, matchers.HasLength(len(returned_list))) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_domain_role_check(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['domains', domain_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, - user=user_id) - - def test_domain_role_check_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'domains', domain_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_project_role_check_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'projects', project_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], project=project_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_domain_group_role_check(self): - return - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['domains', domain_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, group=group_id) - - def test_domain_group_role_check_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'domains', domain_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], domain=domain_id, - group=group_id, os_inherit_extension_inherited=True) - - def test_project_group_role_check_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['OS-INHERIT', - 'projects', project_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.check(role=ref['id'], project=project_id, - group=group_id, os_inherit_extension_inherited=True) - - def test_domain_role_revoke(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['domains', domain_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], domain=domain_id, user=user_id) - - def test_domain_group_role_revoke(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['domains', domain_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], domain=domain_id, group=group_id) - - def test_domain_role_revoke_inherited(self): - user_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'domains', domain_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.revoke(role=ref['id'], domain=domain_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_project_role_revoke_inherited(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'projects', project_id, 'users', user_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, - user=user_id, os_inherit_extension_inherited=True) - - def test_domain_group_role_revoke_inherited(self): - group_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'domains', domain_id, 'groups', group_id, - self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=200) - - self.manager.revoke(role=ref['id'], domain=domain_id, - group=group_id, - os_inherit_extension_inherited=True) - - def test_project_group_role_revoke_inherited(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['OS-INHERIT', 'projects', project_id, 'groups', - group_id, self.collection_key, ref['id'], - 'inherited_to_projects'], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, - group=group_id, - os_inherit_extension_inherited=True) - - def test_project_role_grant(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['projects', project_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], project=project_id, user=user_id) - - def test_project_group_role_grant(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('PUT', - ['projects', project_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=201) - - self.manager.grant(role=ref['id'], project=project_id, group=group_id) - - def test_project_role_list(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['projects', project_id, 'users', user_id, - self.collection_key], entity=ref_list) - - self.manager.list(project=project_id, user=user_id) - - def test_project_group_role_list(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['projects', project_id, 'groups', group_id, - self.collection_key], entity=ref_list) - - self.manager.list(project=project_id, group=group_id) - - def test_project_role_check(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['projects', project_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=200) - - self.manager.check(role=ref['id'], project=project_id, user=user_id) - - def test_project_group_role_check(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['projects', project_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=200) - - self.manager.check(role=ref['id'], project=project_id, group=group_id) - - def test_project_role_revoke(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['projects', project_id, 'users', user_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, user=user_id) - - def test_project_group_role_revoke(self): - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['projects', project_id, 'groups', group_id, - self.collection_key, ref['id']], - status_code=204) - - self.manager.revoke(role=ref['id'], project=project_id, group=group_id) - - def test_domain_project_role_grant_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.grant, - role=ref['id'], - domain=domain_id, - project=project_id, - user=user_id) - - def test_domain_project_role_list_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - - self.assertRaises( - exceptions.ValidationError, - self.manager.list, - domain=domain_id, - project=project_id, - user=user_id) - - def test_domain_project_role_check_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.check, - role=ref['id'], - domain=domain_id, - project=project_id, - user=user_id) - - def test_domain_project_role_revoke_fails(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - domain_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.revoke, - role=ref['id'], - domain=domain_id, - project=project_id, - user=user_id) - - def test_user_group_role_grant_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.grant, - role=ref['id'], - project=project_id, - group=group_id, - user=user_id) - - def test_user_group_role_list_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - - self.assertRaises( - exceptions.ValidationError, - self.manager.list, - project=project_id, - group=group_id, - user=user_id) - - def test_user_group_role_check_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.check, - role=ref['id'], - project=project_id, - group=group_id, - user=user_id) - - def test_user_group_role_revoke_fails(self): - user_id = uuid.uuid4().hex - group_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - ref = self.new_ref() - - self.assertRaises( - exceptions.ValidationError, - self.manager.revoke, - role=ref['id'], - project=project_id, - group=group_id, - user=user_id) - - -class DeprecatedImpliedRoleTests(utils.ClientTestCase): - def setUp(self): - super(DeprecatedImpliedRoleTests, self).setUp() - self.key = 'role' - self.collection_key = 'roles' - self.model = roles.Role - self.manager = self.client.roles - - def test_implied_create(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": { - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }, - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - } - } - - self.stub_url('PUT', - ['roles', prior_id, 'implies', implied_id], - json=mock_response, - status_code=201) - - with self.deprecations.expect_deprecations_here(): - manager_result = self.manager.create_implied(prior_id, implied_id) - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - -class ImpliedRoleTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ImpliedRoleTests, self).setUp() - self.key = 'role_inference' - self.collection_key = 'role_inferences' - self.model = roles.InferenceRule - self.manager = self.client.inference_rules - - def test_check(self): - prior_role_id = uuid.uuid4().hex - implied_role_id = uuid.uuid4().hex - self.stub_url('HEAD', - ['roles', prior_role_id, 'implies', implied_role_id], - status_code=200) - - result = self.manager.check(prior_role_id, implied_role_id) - self.assertTrue(result) - - def test_get(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": { - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }, - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - } - } - - self.stub_url('GET', - ['roles', prior_id, 'implies', implied_id], - json=mock_response, - status_code=200) - - manager_result = self.manager.get(prior_id, implied_id) - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - def test_create(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": { - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }, - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - } - } - - self.stub_url('PUT', - ['roles', prior_id, 'implies', implied_id], - json=mock_response, - status_code=201) - - manager_result = self.manager.create(prior_id, implied_id) - - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - def test_delete(self): - prior_role_id = uuid.uuid4().hex - implied_role_id = uuid.uuid4().hex - self.stub_url('DELETE', - ['roles', prior_role_id, 'implies', implied_role_id], - status_code=204) - - status, body = self.manager.delete(prior_role_id, implied_role_id) - self.assertEqual(204, status.status_code) - self.assertIsNone(body) - - def test_list_role_inferences(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inferences": [{ - "implies": [{ - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }], - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - }] - } - - self.stub_url('GET', - ['role_inferences'], - json=mock_response, - status_code=200) - manager_result = self.manager.list_inference_roles() - self.assertEqual(1, len(manager_result)) - self.assertIsInstance(manager_result[0], roles.InferenceRule) - self.assertEqual(mock_response['role_inferences'][0]['implies'], - manager_result[0].implies) - self.assertEqual(mock_response['role_inferences'][0]['prior_role'], - manager_result[0].prior_role) - - def test_list(self): - prior_id = uuid.uuid4().hex - prior_name = uuid.uuid4().hex - implied_id = uuid.uuid4().hex - implied_name = uuid.uuid4().hex - - mock_response = { - "role_inference": { - "implies": [{ - "id": implied_id, - "links": {"self": "http://host/v3/roles/%s" % implied_id}, - "name": implied_name - }], - "prior_role": { - "id": prior_id, - "links": {"self": "http://host/v3/roles/%s" % prior_id}, - "name": prior_name - } - }, - "links": {"self": "http://host/v3/roles/%s/implies" % prior_id} - } - - self.stub_url('GET', - ['roles', prior_id, 'implies'], - json=mock_response, - status_code=200) - - manager_result = self.manager.list(prior_id) - self.assertIsInstance(manager_result, roles.InferenceRule) - self.assertEqual(1, len(manager_result.implies)) - self.assertEqual(mock_response['role_inference']['implies'], - manager_result.implies) - self.assertEqual(mock_response['role_inference']['prior_role'], - manager_result.prior_role) - - def test_update(self): - # Update not supported for rule inferences - self.assertRaises(exceptions.MethodNotImplemented, self.manager.update) - - def test_find(self): - # Find not supported for rule inferences - self.assertRaises(exceptions.MethodNotImplemented, self.manager.find) - - def test_put(self): - # Put not supported for rule inferences - self.assertRaises(exceptions.MethodNotImplemented, self.manager.put) - - def test_list_params(self): - # Put not supported for rule inferences - self.skipTest("list params not supported by rule inferences") diff --git a/keystoneclient/tests/unit/v3/test_service_catalog.py b/keystoneclient/tests/unit/v3/test_service_catalog.py deleted file mode 100644 index bdd92ceb..00000000 --- a/keystoneclient/tests/unit/v3/test_service_catalog.py +++ /dev/null @@ -1,279 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1 import fixture - -from keystoneclient import access -from keystoneclient import exceptions -from keystoneclient.tests.unit import utils as test_utils -from keystoneclient.tests.unit.v3 import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -class ServiceCatalogTest(utils.TestCase): - def setUp(self): - super(ServiceCatalogTest, self).setUp() - self.AUTH_RESPONSE_BODY = client_fixtures.auth_response_body() - self.RESPONSE = test_utils.test_response( - headers=client_fixtures.AUTH_RESPONSE_HEADERS - ) - - self.north_endpoints = {'public': - 'http://glance.north.host/glanceapi/public', - 'internal': - 'http://glance.north.host/glanceapi/internal', - 'admin': - 'http://glance.north.host/glanceapi/admin'} - - self.south_endpoints = {'public': - 'http://glance.south.host/glanceapi/public', - 'internal': - 'http://glance.south.host/glanceapi/internal', - 'admin': - 'http://glance.south.host/glanceapi/admin'} - - def test_building_a_service_catalog(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - self.assertEqual(sc.url_for(service_type='compute'), - "https://compute.north.host/novapi/public") - self.assertEqual(sc.url_for(service_type='compute', - endpoint_type='internal'), - "https://compute.north.host/novapi/internal") - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, "region", - "South", service_type='compute') - - def test_service_catalog_endpoints(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - public_ep = sc.get_endpoints(service_type='compute', - endpoint_type='public') - self.assertEqual(public_ep['compute'][0]['region'], 'North') - self.assertEqual(public_ep['compute'][0]['url'], - "https://compute.north.host/novapi/public") - - def test_service_catalog_regions(self): - self.AUTH_RESPONSE_BODY['token']['region_name'] = "North" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', endpoint_type='public') - self.assertEqual(url, "http://glance.north.host/glanceapi/public") - - self.AUTH_RESPONSE_BODY['token']['region_name'] = "South" - # Setting region_name on the catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - url = sc.url_for(service_type='image', endpoint_type='internal') - self.assertEqual(url, "http://glance.south.host/glanceapi/internal") - - def test_service_catalog_empty(self): - self.AUTH_RESPONSE_BODY['token']['catalog'] = [] - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - self.assertRaises(exceptions.EmptyCatalog, - auth_ref.service_catalog.url_for, - service_type='image', - endpoint_type='internalURL') - - def test_service_catalog_get_endpoints_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - endpoints = sc.get_endpoints(service_type='image', region_name='North') - self.assertEqual(len(endpoints), 1) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.north_endpoints[endpoint['interface']]) - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints), 1) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.south_endpoints[endpoint['interface']]) - - endpoints = sc.get_endpoints(service_type='compute') - self.assertEqual(len(endpoints['compute']), 3) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='North') - self.assertEqual(len(endpoints['compute']), 3) - - endpoints = sc.get_endpoints(service_type='compute', - region_name='West') - self.assertEqual(len(endpoints['compute']), 0) - - def test_service_catalog_url_for_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image', region_name='North') - self.assertEqual(url, self.north_endpoints['public']) - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, self.south_endpoints['public']) - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_type='image', region_name='West') - - def test_servcie_catalog_get_url_region_names(self): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - urls = sc.get_urls(service_type='image') - self.assertEqual(len(urls), 2) - - urls = sc.get_urls(service_type='image', region_name='North') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], self.north_endpoints['public']) - - urls = sc.get_urls(service_type='image', region_name='South') - self.assertEqual(len(urls), 1) - self.assertEqual(urls[0], self.south_endpoints['public']) - - urls = sc.get_urls(service_type='image', region_name='West') - self.assertIsNone(urls) - - def test_service_catalog_param_overrides_body_region(self): - self.AUTH_RESPONSE_BODY['token']['region_name'] = "North" - # Passing region_name to service catalog is deprecated. - with self.deprecations.expect_deprecations_here(): - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_type='image') - self.assertEqual(url, self.north_endpoints['public']) - - url = sc.url_for(service_type='image', region_name='South') - self.assertEqual(url, self.south_endpoints['public']) - - endpoints = sc.get_endpoints(service_type='image') - self.assertEqual(len(endpoints['image']), 3) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.north_endpoints[endpoint['interface']]) - - endpoints = sc.get_endpoints(service_type='image', region_name='South') - self.assertEqual(len(endpoints['image']), 3) - for endpoint in endpoints['image']: - self.assertEqual(endpoint['url'], - self.south_endpoints[endpoint['interface']]) - - def test_service_catalog_service_name(self): - auth_ref = access.AccessInfo.factory(resp=None, - body=self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - url = sc.url_for(service_name='glance', endpoint_type='public', - service_type='image', region_name='North') - self.assertEqual('http://glance.north.host/glanceapi/public', url) - - url = sc.url_for(service_name='glance', endpoint_type='public', - service_type='image', region_name='South') - self.assertEqual('http://glance.south.host/glanceapi/public', url) - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, - service_name='glance', service_type='compute') - - urls = sc.get_urls(service_type='image', service_name='glance', - endpoint_type='public') - - self.assertIn('http://glance.north.host/glanceapi/public', urls) - self.assertIn('http://glance.south.host/glanceapi/public', urls) - - urls = sc.get_urls(service_type='image', service_name='Servers', - endpoint_type='public') - - self.assertIsNone(urls) - - def test_service_catalog_without_name(self): - pr_auth_ref = access.AccessInfo.factory( - resp=None, - body=client_fixtures.project_scoped_token()) - pr_sc = pr_auth_ref.service_catalog - - # this will work because there are no service names on that token - url_ref = 'http://public.com:8774/v2/225da22d3ce34b15877ea70b2a575f58' - url = pr_sc.url_for(service_type='compute', service_name='NotExist', - endpoint_type='public') - self.assertEqual(url_ref, url) - - ab_auth_ref = access.AccessInfo.factory(resp=None, - body=self.AUTH_RESPONSE_BODY) - ab_sc = ab_auth_ref.service_catalog - - # this won't work because there is a name and it's not this one - self.assertRaises(exceptions.EndpointNotFound, ab_sc.url_for, - service_type='compute', service_name='NotExist', - endpoint_type='public') - - -class ServiceCatalogV3Test(ServiceCatalogTest): - - def test_building_a_service_catalog(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - self.assertEqual(sc.url_for(service_type='compute'), - 'https://compute.north.host/novapi/public') - self.assertEqual(sc.url_for(service_type='compute', - endpoint_type='internal'), - 'https://compute.north.host/novapi/internal') - - self.assertRaises(exceptions.EndpointNotFound, sc.url_for, 'region_id', - 'South', service_type='compute') - - def test_service_catalog_endpoints(self): - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) - sc = auth_ref.service_catalog - - public_ep = sc.get_endpoints(service_type='compute', - endpoint_type='public') - self.assertEqual(public_ep['compute'][0]['region_id'], 'North') - self.assertEqual(public_ep['compute'][0]['url'], - 'https://compute.north.host/novapi/public') - - def test_service_catalog_multiple_service_types(self): - token = fixture.V3Token() - token.set_project_scope() - - for i in range(3): - s = token.add_service('compute') - s.add_standard_endpoints(public='public-%d' % i, - admin='admin-%d' % i, - internal='internal-%d' % i, - region='region-%d' % i) - - auth_ref = access.AccessInfo.factory(resp=None, body=token) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='public') - - self.assertEqual(set(['public-0', 'public-1', 'public-2']), set(urls)) - - urls = auth_ref.service_catalog.get_urls(service_type='compute', - endpoint_type='public', - region_name='region-1') - - self.assertEqual(('public-1', ), urls) diff --git a/keystoneclient/tests/unit/v3/test_services.py b/keystoneclient/tests/unit/v3/test_services.py deleted file mode 100644 index 9bda5dbb..00000000 --- a/keystoneclient/tests/unit/v3/test_services.py +++ /dev/null @@ -1,44 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import services - - -class ServiceTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(ServiceTests, self).setUp() - self.key = 'service' - self.collection_key = 'services' - self.model = services.Service - self.manager = self.client.services - - def new_ref(self, **kwargs): - kwargs = super(ServiceTests, self).new_ref(**kwargs) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('type', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - return kwargs - - def test_list_filter_name(self): - filter_name = uuid.uuid4().hex - expected_query = {'name': filter_name} - super(ServiceTests, self).test_list(expected_query=expected_query, - name=filter_name) - - def test_list_filter_type(self): - filter_type = uuid.uuid4().hex - expected_query = {'type': filter_type} - super(ServiceTests, self).test_list(expected_query=expected_query, - type=filter_type) diff --git a/keystoneclient/tests/unit/v3/test_simple_cert.py b/keystoneclient/tests/unit/v3/test_simple_cert.py deleted file mode 100644 index 1c4a245d..00000000 --- a/keystoneclient/tests/unit/v3/test_simple_cert.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 IBM Corp. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testresources - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -class SimpleCertTests(utils.ClientTestCase, testresources.ResourcedTestCase): - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_get_ca_certificate(self): - self.stub_url('GET', ['OS-SIMPLE-CERT', 'ca'], - headers={'Content-Type': 'application/x-pem-file'}, - text=self.examples.SIGNING_CA) - res = self.client.simple_cert.get_ca_certificates() - self.assertEqual(self.examples.SIGNING_CA, res) - - def test_get_certificates(self): - self.stub_url('GET', ['OS-SIMPLE-CERT', 'certificates'], - headers={'Content-Type': 'application/x-pem-file'}, - text=self.examples.SIGNING_CERT) - res = self.client.simple_cert.get_certificates() - self.assertEqual(self.examples.SIGNING_CERT, res) - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v3/test_tokens.py b/keystoneclient/tests/unit/v3/test_tokens.py deleted file mode 100644 index 89b65f84..00000000 --- a/keystoneclient/tests/unit/v3/test_tokens.py +++ /dev/null @@ -1,163 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from keystoneauth1 import exceptions -import testresources - -from keystoneclient import access -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit.v3 import utils - - -class TokenTests(utils.ClientTestCase, testresources.ResourcedTestCase): - - resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] - - def test_revoke_token_with_token_id(self): - token_id = uuid.uuid4().hex - self.stub_url('DELETE', ['/auth/tokens'], status_code=204) - self.client.tokens.revoke_token(token_id) - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - - def test_revoke_token_with_access_info_instance(self): - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - token = access.AccessInfoV3(token_id, token_ref['token']) - self.stub_url('DELETE', ['/auth/tokens'], status_code=204) - self.client.tokens.revoke_token(token) - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - - def test_get_revoked(self): - sample_revoked_response = {'signed': '-----BEGIN CMS-----\nMIIB...'} - self.stub_url('GET', ['auth', 'tokens', 'OS-PKI', 'revoked'], - json=sample_revoked_response) - resp = self.client.tokens.get_revoked() - self.assertQueryStringIs() - self.assertEqual(sample_revoked_response, resp) - - def test_get_revoked_audit_id_only(self): - # When get_revoked(audit_id_only=True) then ?audit_id_only is set on - # the request. - sample_revoked_response = { - 'revoked': [ - { - 'audit_id': uuid.uuid4().hex, - 'expires': '2016-01-21T15:53:52Z', - }, - ], - } - self.stub_url('GET', ['auth', 'tokens', 'OS-PKI', 'revoked'], - json=sample_revoked_response) - resp = self.client.tokens.get_revoked(audit_id_only=True) - self.assertQueryStringIs('audit_id_only') - self.assertEqual(sample_revoked_response, resp) - - def test_get_revoked_audit_id_only_positional_exc(self): - # When get_revoked(True) an exception is raised because this must be - # called with named parameter. - self.assertRaises(TypeError, self.client.tokens.get_revoked, True) - - def test_validate_token_with_token_id(self): - # Can validate a token passing a string token ID. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - token_data = self.client.tokens.get_token_data(token_id) - self.assertEqual(token_data, token_ref) - - access_info = self.client.tokens.validate(token_id) - - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - self.assertIsInstance(access_info, access.AccessInfoV3) - self.assertEqual(token_id, access_info.auth_token) - - def test_validate_token_with_access_info(self): - # Can validate a token passing an access info. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - token = access.AccessInfoV3(token_id, token_ref['token']) - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - access_info = self.client.tokens.validate(token) - - self.assertRequestHeaderEqual('X-Subject-Token', token_id) - self.assertIsInstance(access_info, access.AccessInfoV3) - self.assertEqual(token_id, access_info.auth_token) - - def test_validate_token_invalid(self): - # When the token is invalid the server typically returns a 404. - token_id = uuid.uuid4().hex - self.stub_url('GET', ['auth', 'tokens'], status_code=404) - - self.assertRaises(exceptions.NotFound, - self.client.tokens.get_token_data, token_id) - self.assertRaises(exceptions.NotFound, - self.client.tokens.validate, token_id) - - def test_validate_token_catalog(self): - # Can validate a token and a catalog is requested by default. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_DEFAULT] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - token_data = self.client.tokens.get_token_data(token_id) - self.assertQueryStringIs() - self.assertIn('catalog', token_data['token']) - - access_info = self.client.tokens.validate(token_id) - - self.assertQueryStringIs() - self.assertTrue(access_info.has_service_catalog()) - - def test_validate_token_nocatalog(self): - # Can validate a token and request no catalog. - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_UNSCOPED] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - token_data = self.client.tokens.get_token_data(token_id) - self.assertQueryStringIs() - self.assertNotIn('catalog', token_data['token']) - - access_info = self.client.tokens.validate(token_id, - include_catalog=False) - - self.assertQueryStringIs('nocatalog') - self.assertFalse(access_info.has_service_catalog()) - - def test_validate_token_allow_expired(self): - token_id = uuid.uuid4().hex - token_ref = self.examples.TOKEN_RESPONSES[ - self.examples.v3_UUID_TOKEN_UNSCOPED] - self.stub_url('GET', ['auth', 'tokens'], - headers={'X-Subject-Token': token_id, }, json=token_ref) - - self.client.tokens.validate(token_id) - self.assertQueryStringIs() - - self.client.tokens.validate(token_id, allow_expired=True) - self.assertQueryStringIs('allow_expired=1') - - -def load_tests(loader, tests, pattern): - return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/unit/v3/test_trusts.py b/keystoneclient/tests/unit/v3/test_trusts.py deleted file mode 100644 index 1c74ac9b..00000000 --- a/keystoneclient/tests/unit/v3/test_trusts.py +++ /dev/null @@ -1,128 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import uuid - -from oslo_utils import timeutils - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3.contrib import trusts - - -class TrustTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(TrustTests, self).setUp() - self.key = 'trust' - self.collection_key = 'trusts' - self.model = trusts.Trust - self.manager = self.client.trusts - self.path_prefix = 'OS-TRUST' - - def new_ref(self, **kwargs): - kwargs = super(TrustTests, self).new_ref(**kwargs) - kwargs.setdefault('project_id', uuid.uuid4().hex) - return kwargs - - def test_create(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - super(TrustTests, self).test_create(ref=ref) - - def test_create_limited_uses(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - ref['remaining_uses'] = 5 - super(TrustTests, self).test_create(ref=ref) - - def test_create_roles(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - req_ref = ref.copy() - req_ref.pop('id') - - # Note the TrustManager takes a list of role_names, and converts - # internally to the slightly odd list-of-dict API format, so we - # have to pass the expected request data to allow correct stubbing - ref['role_names'] = ['atestrole'] - req_ref['roles'] = [{'name': 'atestrole'}] - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_create_role_id_and_names(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - req_ref = ref.copy() - req_ref.pop('id') - - # Note the TrustManager takes a list of role_names, and converts - # internally to the slightly odd list-of-dict API format, so we - # have to pass the expected request data to allow correct stubbing - ref['role_names'] = ['atestrole'] - ref['role_ids'] = [uuid.uuid4().hex] - req_ref['roles'] = [{'name': 'atestrole'}, {'id': ref['role_ids'][0]}] - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_create_expires(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = False - ref['expires_at'] = timeutils.parse_isotime( - '2013-03-04T12:00:01.000000Z') - req_ref = ref.copy() - req_ref.pop('id') - - # Note the TrustManager takes a datetime.datetime object for - # expires_at, and converts it internally into an iso format datestamp - req_ref['expires_at'] = '2013-03-04T12:00:01.000000Z' - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_create_imp(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = True - super(TrustTests, self).test_create(ref=ref) - - def test_create_roles_imp(self): - ref = self.new_ref() - ref['trustor_user_id'] = uuid.uuid4().hex - ref['trustee_user_id'] = uuid.uuid4().hex - ref['impersonation'] = True - req_ref = ref.copy() - req_ref.pop('id') - ref['role_names'] = ['atestrole'] - req_ref['roles'] = [{'name': 'atestrole'}] - super(TrustTests, self).test_create(ref=ref, req_ref=req_ref) - - def test_list_filter_trustor(self): - expected_query = {'trustor_user_id': '12345'} - super(TrustTests, self).test_list(expected_query=expected_query, - trustor_user='12345') - - def test_list_filter_trustee(self): - expected_query = {'trustee_user_id': '12345'} - super(TrustTests, self).test_list(expected_query=expected_query, - trustee_user='12345') - - def test_update(self): - # Update not supported for the OS-TRUST API - self.assertRaises(exceptions.MethodNotImplemented, self.manager.update) diff --git a/keystoneclient/tests/unit/v3/test_users.py b/keystoneclient/tests/unit/v3/test_users.py deleted file mode 100644 index e0a34461..00000000 --- a/keystoneclient/tests/unit/v3/test_users.py +++ /dev/null @@ -1,309 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import uuid - -from keystoneclient import exceptions -from keystoneclient.tests.unit.v3 import utils -from keystoneclient.v3 import users - - -class UserTests(utils.ClientTestCase, utils.CrudTests): - def setUp(self): - super(UserTests, self).setUp() - self.key = 'user' - self.collection_key = 'users' - self.model = users.User - self.manager = self.client.users - - def new_ref(self, **kwargs): - kwargs = super(UserTests, self).new_ref(**kwargs) - kwargs.setdefault('description', uuid.uuid4().hex) - kwargs.setdefault('domain_id', uuid.uuid4().hex) - kwargs.setdefault('enabled', True) - kwargs.setdefault('name', uuid.uuid4().hex) - kwargs.setdefault('default_project_id', uuid.uuid4().hex) - return kwargs - - def test_add_user_to_group(self): - group_id = uuid.uuid4().hex - ref = self.new_ref() - self.stub_url('PUT', - ['groups', group_id, self.collection_key, ref['id']], - status_code=204) - - self.manager.add_to_group(user=ref['id'], group=group_id) - self.assertRaises(exceptions.ValidationError, - self.manager.remove_from_group, - user=ref['id'], - group=None) - - def test_list_users_in_group(self): - group_id = uuid.uuid4().hex - ref_list = [self.new_ref(), self.new_ref()] - - self.stub_entity('GET', - ['groups', group_id, self.collection_key], - entity=ref_list) - - returned_list = self.manager.list(group=group_id) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - def test_check_user_in_group(self): - group_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('HEAD', - ['groups', group_id, self.collection_key, ref['id']], - status_code=204) - - self.manager.check_in_group(user=ref['id'], group=group_id) - - self.assertRaises(exceptions.ValidationError, - self.manager.check_in_group, - user=ref['id'], - group=None) - - def test_remove_user_from_group(self): - group_id = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_url('DELETE', - ['groups', group_id, self.collection_key, ref['id']], - status_code=204) - - self.manager.remove_from_group(user=ref['id'], group=group_id) - self.assertRaises(exceptions.ValidationError, - self.manager.remove_from_group, - user=ref['id'], - group=None) - - def test_create_doesnt_log_password(self): - password = uuid.uuid4().hex - ref = self.new_ref() - - self.stub_entity('POST', [self.collection_key], - status_code=201, entity=ref) - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - param_ref['password'] = password - params = utils.parameterize(param_ref) - - self.manager.create(**params) - - self.assertNotIn(password, self.logger.output) - - def test_create_with_project(self): - # Can create a user with the deprecated project option rather than - # default_project_id. - self.deprecations.expect_deprecations() - ref = self.new_ref() - - self.stub_entity('POST', [self.collection_key], - status_code=201, entity=ref) - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - # Use deprecated project_id rather than new default_project_id. - param_ref['project_id'] = param_ref.pop('default_project_id') - params = utils.parameterize(param_ref) - - returned = self.manager.create(**params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_create_with_project_and_default_project(self): - # Can create a user with the deprecated project and default_project_id. - # The backend call should only pass the default_project_id. - self.deprecations.expect_deprecations() - - ref = self.new_ref() - - self.stub_entity('POST', - [self.collection_key], - status_code=201, entity=ref) - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - # Add the deprecated project_id in the call, the value will be ignored. - param_ref['project_id'] = 'project' - params = utils.parameterize(param_ref) - - returned = self.manager.create(**params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_update_doesnt_log_password(self): - password = uuid.uuid4().hex - ref = self.new_ref() - - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - self.stub_entity('PATCH', - [self.collection_key, ref['id']], - status_code=200, entity=ref) - - param_ref['password'] = password - params = utils.parameterize(param_ref) - - self.manager.update(ref['id'], **params) - - self.assertNotIn(password, self.logger.output) - - def test_update_with_project(self): - # Can update a user with the deprecated project option rather than - # default_project_id. - self.deprecations.expect_deprecations() - - ref = self.new_ref() - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - self.stub_entity('PATCH', - [self.collection_key, ref['id']], - status_code=200, entity=ref) - - # Use deprecated project_id rather than new default_project_id. - param_ref['project_id'] = param_ref.pop('default_project_id') - params = utils.parameterize(param_ref) - - returned = self.manager.update(ref['id'], **params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_update_with_project_and_default_project(self, ref=None): - self.deprecations.expect_deprecations() - - ref = self.new_ref() - req_ref = ref.copy() - req_ref.pop('id') - param_ref = req_ref.copy() - - self.stub_entity('PATCH', - [self.collection_key, ref['id']], - status_code=200, entity=ref) - - # Add the deprecated project_id in the call, the value will be ignored. - param_ref['project_id'] = 'project' - params = utils.parameterize(param_ref) - - returned = self.manager.update(ref['id'], **params) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_update_password(self): - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - - self.stub_url('POST', - [self.collection_key, self.TEST_USER_ID, 'password']) - self.client.user_id = self.TEST_USER_ID - self.manager.update_password(old_password, new_password) - - exp_req_body = { - 'user': { - 'password': new_password, 'original_password': old_password - } - } - - self.assertEqual( - '%s/users/%s/password' % (self.TEST_URL, self.TEST_USER_ID), - self.requests_mock.last_request.url) - self.assertRequestBodyIs(json=exp_req_body) - self.assertNotIn(old_password, self.logger.output) - self.assertNotIn(new_password, self.logger.output) - - def test_update_password_with_no_hardcoded_endpoint_filter(self): - # test to ensure the 'endpoint_filter' parameter is not being - # passed from the manager. Endpoint filtering should be done at - # the Session, not the individual managers. - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - expected_params = {'user': {'password': new_password, - 'original_password': old_password}} - user_password_update_path = '/users/%s/password' % self.TEST_USER_ID - - self.client.user_id = self.TEST_USER_ID - # NOTE(gyee): user manager subclass keystoneclient.base.Manager - # and utilize the _update() method in the base class to interface - # with the client session to perform the update. In the case, we - # just need to make sure the 'endpoint_filter' parameter is not - # there. - with mock.patch('keystoneclient.base.Manager._update') as m: - self.manager.update_password(old_password, new_password) - m.assert_called_with(user_password_update_path, expected_params, - method='POST', log=False) - - def test_update_password_with_bad_inputs(self): - old_password = uuid.uuid4().hex - new_password = uuid.uuid4().hex - - # users can't unset their password - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - old_password, None) - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - old_password, '') - - # users can't start with empty passwords - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - None, new_password) - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - '', new_password) - - # this wouldn't result in any change anyway - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - None, None) - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - '', '') - password = uuid.uuid4().hex - self.assertRaises(exceptions.ValidationError, - self.manager.update_password, - password, password) diff --git a/keystoneclient/tests/unit/v3/utils.py b/keystoneclient/tests/unit/v3/utils.py deleted file mode 100644 index d9cb5a47..00000000 --- a/keystoneclient/tests/unit/v3/utils.py +++ /dev/null @@ -1,373 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from six.moves.urllib import parse as urlparse - -from keystoneclient.tests.unit import client_fixtures -from keystoneclient.tests.unit import utils - - -def parameterize(ref): - """Rewrite attributes to match the kwarg naming convention in client. - - >>> parameterize({'project_id': 0}) - {'project': 0} - - """ - params = ref.copy() - for key in ref: - if key[-3:] == '_id': - params.setdefault(key[:-3], params.pop(key)) - return params - - -class UnauthenticatedTestCase(utils.TestCase): - """Class used as base for unauthenticated calls.""" - - TEST_ROOT_URL = 'http://127.0.0.1:5000/' - TEST_URL = '%s%s' % (TEST_ROOT_URL, 'v3') - TEST_ROOT_ADMIN_URL = 'http://127.0.0.1:35357/' - TEST_ADMIN_URL = '%s%s' % (TEST_ROOT_ADMIN_URL, 'v3') - - -class TestCase(UnauthenticatedTestCase): - - TEST_ADMIN_IDENTITY_ENDPOINT = "http://127.0.0.1:35357/v3" - - TEST_SERVICE_CATALOG = [{ - "endpoints": [{ - "url": "http://cdn.admin-nets.local:8774/v1.0/", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:8774/v1.0", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://cdn.admin-nets.local:8774/v1.0", - "region": "RegionOne", - "interface": "admin" - }], - "type": "nova_compat" - }, { - "endpoints": [{ - "url": "http://nova/novapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://nova/novapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://nova/novapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "compute" - }, { - "endpoints": [{ - "url": "http://glance/glanceapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://glance/glanceapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://glance/glanceapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "image", - "name": "glance" - }, { - "endpoints": [{ - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://127.0.0.1:5000/v3", - "region": "RegionOne", - "interface": "internal" - }, { - "url": TEST_ADMIN_IDENTITY_ENDPOINT, - "region": "RegionOne", - "interface": "admin" - }], - "type": "identity" - }, { - "endpoints": [{ - "url": "http://swift/swiftapi/public", - "region": "RegionOne", - "interface": "public" - }, { - "url": "http://swift/swiftapi/internal", - "region": "RegionOne", - "interface": "internal" - }, { - "url": "http://swift/swiftapi/admin", - "region": "RegionOne", - "interface": "admin" - }], - "type": "object-store" - }] - - def stub_auth(self, subject_token=None, **kwargs): - - if not subject_token: - subject_token = self.TEST_TOKEN - - try: - response_list = kwargs['response_list'] - except KeyError: - headers = kwargs.setdefault('headers', {}) - headers['X-Subject-Token'] = subject_token - else: - for resp in response_list: - headers = resp.setdefault('headers', {}) - headers['X-Subject-Token'] = subject_token - - self.stub_url('POST', ['auth', 'tokens'], **kwargs) - - -class ClientTestCase(utils.ClientTestCaseMixin, TestCase): - - ORIGINAL_CLIENT_TYPE = 'original' - KSC_SESSION_CLIENT_TYPE = 'ksc-session' - KSA_SESSION_CLIENT_TYPE = 'ksa-session' - - scenarios = [ - ( - ORIGINAL_CLIENT_TYPE, { - 'client_fixture_class': client_fixtures.OriginalV3, - 'client_type': ORIGINAL_CLIENT_TYPE - } - ), - ( - KSC_SESSION_CLIENT_TYPE, { - 'client_fixture_class': client_fixtures.KscSessionV3, - 'client_type': KSC_SESSION_CLIENT_TYPE - } - ), - ( - KSA_SESSION_CLIENT_TYPE, { - 'client_fixture_class': client_fixtures.KsaSessionV3, - 'client_type': KSA_SESSION_CLIENT_TYPE - } - ) - - ] - - @property - def is_original_client(self): - return self.client_type == self.ORIGINAL_CLIENT_TYPE - - @property - def is_session_client(self): - return self.client_type in (self.KSC_SESSION_CLIENT_TYPE, - self.KSA_SESSION_CLIENT_TYPE) - - -class CrudTests(object): - key = None - collection_key = None - model = None - manager = None - path_prefix = None - - def new_ref(self, **kwargs): - kwargs.setdefault('id', uuid.uuid4().hex) - kwargs.setdefault(uuid.uuid4().hex, uuid.uuid4().hex) - return kwargs - - def encode(self, entity): - if isinstance(entity, dict): - return {self.key: entity} - if isinstance(entity, list): - return {self.collection_key: entity} - raise NotImplementedError('Are you sure you want to encode that?') - - def stub_entity(self, method, parts=None, entity=None, id=None, **kwargs): - if entity: - entity = self.encode(entity) - kwargs['json'] = entity - - if not parts: - parts = [self.collection_key] - - if self.path_prefix: - parts.insert(0, self.path_prefix) - - if id: - if not parts: - parts = [] - - parts.append(id) - - self.stub_url(method, parts=parts, **kwargs) - - def assertEntityRequestBodyIs(self, entity): - self.assertRequestBodyIs(json=self.encode(entity)) - - def test_create(self, ref=None, req_ref=None): - ref = ref or self.new_ref() - manager_ref = ref.copy() - manager_ref.pop('id') - - # req_ref argument allows you to specify a different - # signature for the request when the manager does some - # conversion before doing the request (e.g. converting - # from datetime object to timestamp string) - if req_ref: - req_ref = req_ref.copy() - else: - req_ref = ref.copy() - req_ref.pop('id') - - self.stub_entity('POST', entity=req_ref, status_code=201) - - returned = self.manager.create(**parameterize(manager_ref)) - self.assertIsInstance(returned, self.model) - for attr in req_ref: - self.assertEqual( - getattr(returned, attr), - req_ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - # The entity created here may be used in other test cases - return returned - - def test_get(self, ref=None): - ref = ref or self.new_ref() - - self.stub_entity('GET', id=ref['id'], entity=ref) - - returned = self.manager.get(ref['id']) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - - def _get_expected_path(self, expected_path=None): - if not expected_path: - if self.path_prefix: - expected_path = 'v3/%s/%s' % (self.path_prefix, - self.collection_key) - else: - expected_path = 'v3/%s' % self.collection_key - - return expected_path - - def test_list_by_id(self, ref=None, **filter_kwargs): - """Test ``entities.list(id=x)`` being rewritten as ``GET /v3/entities/x``. - - This tests an edge case of each manager's list() implementation, to - ensure that it "does the right thing" when users call ``.list()`` - when they should have used ``.get()``. - - """ - if 'id' not in filter_kwargs: - ref = ref or self.new_ref() - filter_kwargs['id'] = ref['id'] - - self.assertRaises(TypeError, self.manager.list, **filter_kwargs) - - def test_list(self, ref_list=None, expected_path=None, - expected_query=None, **filter_kwargs): - ref_list = ref_list or [self.new_ref(), self.new_ref()] - expected_path = self._get_expected_path(expected_path) - - self.requests_mock.get(urlparse.urljoin(self.TEST_URL, expected_path), - json=self.encode(ref_list)) - - returned_list = self.manager.list(**filter_kwargs) - self.assertEqual(len(ref_list), len(returned_list)) - [self.assertIsInstance(r, self.model) for r in returned_list] - - qs_args = self.requests_mock.last_request.qs - qs_args_expected = expected_query or filter_kwargs - for key, value in qs_args_expected.items(): - self.assertIn(key, qs_args) - # The querystring value is a list. Note we convert the value to a - # string and lower, as the query string is always a string and the - # filter_kwargs may contain non-string values, for example a - # boolean, causing the comaprison to fail. - self.assertIn(str(value).lower(), qs_args[key]) - - # Also check that no query string args exist which are not expected - for key in qs_args: - self.assertIn(key, qs_args_expected) - - def test_list_params(self): - ref_list = [self.new_ref()] - filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} - expected_path = self._get_expected_path() - - self.requests_mock.get(urlparse.urljoin(self.TEST_URL, expected_path), - json=self.encode(ref_list)) - - self.manager.list(**filter_kwargs) - self.assertQueryStringContains(**filter_kwargs) - - def test_find(self, ref=None): - ref = ref or self.new_ref() - ref_list = [ref] - - self.stub_entity('GET', entity=ref_list) - - returned = self.manager.find(name=getattr(ref, 'name', None)) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - - if hasattr(ref, 'name'): - self.assertQueryStringIs('name=%s' % ref['name']) - else: - self.assertQueryStringIs('') - - def test_update(self, ref=None, req_ref=None): - ref = ref or self.new_ref() - - self.stub_entity('PATCH', id=ref['id'], entity=ref) - - # req_ref argument allows you to specify a different - # signature for the request when the manager does some - # conversion before doing the request (e.g. converting - # from datetime object to timestamp string) - if req_ref: - req_ref = req_ref.copy() - else: - req_ref = ref.copy() - req_ref.pop('id') - - returned = self.manager.update(ref['id'], **parameterize(req_ref)) - self.assertIsInstance(returned, self.model) - for attr in ref: - self.assertEqual( - getattr(returned, attr), - ref[attr], - 'Expected different %s' % attr) - self.assertEntityRequestBodyIs(req_ref) - - def test_delete(self, ref=None): - ref = ref or self.new_ref() - - self.stub_entity('DELETE', id=ref['id'], status_code=204) - self.manager.delete(ref['id']) diff --git a/keystoneclient/utils.py b/keystoneclient/utils.py deleted file mode 100644 index 8e8dd7c7..00000000 --- a/keystoneclient/utils.py +++ /dev/null @@ -1,126 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import getpass -import hashlib -import sys - -from keystoneauth1 import exceptions as ksa_exceptions -from oslo_utils import timeutils -# NOTE(stevemar): do not remove positional. We need this to stay for a while -# since versions of auth_token require it here. -from positional import positional # noqa -import six - -from keystoneclient import exceptions as ksc_exceptions - - -def find_resource(manager, name_or_id): - """Helper for the _find_* methods.""" - # first try the entity as a string - try: - return manager.get(name_or_id) - except (ksa_exceptions.NotFound): # nosec(cjschaef): try to find - # 'name_or_id' as a six.binary_type instead - pass - - # finally try to find entity by name - try: - if isinstance(name_or_id, six.binary_type): - name_or_id = name_or_id.decode('utf-8', 'strict') - return manager.find(name=name_or_id) - except ksa_exceptions.NotFound: - msg = ("No %s with a name or ID of '%s' exists." % - (manager.resource_class.__name__.lower(), name_or_id)) - raise ksc_exceptions.CommandError(msg) - except ksc_exceptions.NoUniqueMatch: - msg = ("Multiple %s matches found for '%s', use an ID to be more" - " specific." % (manager.resource_class.__name__.lower(), - name_or_id)) - raise ksc_exceptions.CommandError(msg) - - -def hash_signed_token(signed_text, mode='md5'): - hash_ = hashlib.new(mode) - hash_.update(signed_text) - return hash_.hexdigest() - - -def prompt_user_password(): - """Prompt user for a password. - - Prompt for a password if stdin is a tty. - """ - password = None - - # If stdin is a tty, try prompting for the password - if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty(): - # Check for Ctl-D - try: - password = getpass.getpass('Password: ') - except EOFError: # nosec(cjschaef): return password, which is None if - # password was not found - pass - - return password - - -def prompt_for_password(): - """Prompt user for password if not provided. - - Prompt is used so the password doesn't show up in the - bash history. - """ - if not (hasattr(sys.stdin, 'isatty') and sys.stdin.isatty()): - # nothing to do - return - - while True: - try: - new_passwd = getpass.getpass('New Password: ') - rep_passwd = getpass.getpass('Repeat New Password: ') - if new_passwd == rep_passwd: - return new_passwd - except EOFError: - return - - -_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' -_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' - - -def isotime(at=None, subsecond=False): - """Stringify time in ISO 8601 format.""" - # Python provides a similar instance method for datetime.datetime objects - # called isoformat(). The format of the strings generated by isoformat() - # have a couple of problems: - # 1) The strings generated by isotime are used in tokens and other public - # APIs that we can't change without a deprecation period. The strings - # generated by isoformat are not the same format, so we can't just - # change to it. - # 2) The strings generated by isoformat do not include the microseconds if - # the value happens to be 0. This will likely show up as random failures - # as parsers may be written to always expect microseconds, and it will - # parse correctly most of the time. - if not at: - at = timeutils.utcnow() - st = at.strftime(_ISO8601_TIME_FORMAT - if not subsecond - else _ISO8601_TIME_FORMAT_SUBSECOND) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - st += ('Z' if tz == 'UTC' else tz) - return st - - -def strtime(at=None): - at = at or timeutils.utcnow() - return at.strftime(timeutils.PERFECT_TIME_FORMAT) diff --git a/keystoneclient/v2_0/__init__.py b/keystoneclient/v2_0/__init__.py deleted file mode 100644 index 23382fea..00000000 --- a/keystoneclient/v2_0/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from keystoneclient.v2_0.client import Client # noqa - - -__all__ = ( - 'client', -) diff --git a/keystoneclient/v2_0/certificates.py b/keystoneclient/v2_0/certificates.py deleted file mode 100644 index 2c69dfb3..00000000 --- a/keystoneclient/v2_0/certificates.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 IBM Corp. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -class CertificatesManager(object): - """Manager for certificates.""" - - def __init__(self, client): - self._client = client - - def get_ca_certificate(self): - """Get CA certificate. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/certificates/ca', authenticated=False) - return resp.text - - def get_signing_certificate(self): - """Get signing certificate. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/certificates/signing', - authenticated=False) - return resp.text diff --git a/keystoneclient/v2_0/client.py b/keystoneclient/v2_0/client.py deleted file mode 100644 index 904f7693..00000000 --- a/keystoneclient/v2_0/client.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import warnings - -from keystoneclient.auth.identity import v2 as v2_auth -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient.i18n import _ -from keystoneclient.v2_0 import certificates -from keystoneclient.v2_0 import ec2 -from keystoneclient.v2_0 import endpoints -from keystoneclient.v2_0 import extensions -from keystoneclient.v2_0 import roles -from keystoneclient.v2_0 import services -from keystoneclient.v2_0 import tenants -from keystoneclient.v2_0 import tokens -from keystoneclient.v2_0 import users - - -_logger = logging.getLogger(__name__) - - -class Client(httpclient.HTTPClient): - """Client for the OpenStack Keystone v2.0 API. - - :param string username: Username for authentication. (optional) - :param string password: Password for authentication. (optional) - :param string token: Token for authentication. (optional) - :param string tenant_id: Tenant id. (optional) - :param string tenant_name: Tenant name. (optional) - :param string auth_url: Keystone service endpoint for authorization. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - :param string endpoint: A user-supplied endpoint URL for the keystone - service. Lazy-authentication is possible for API - service calls if endpoint is set at - instantiation.(optional) - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - :param string original_ip: The original IP of the requesting user - which will be sent to Keystone in a - 'Forwarded' header. (optional) - :param string cert: Path to the Privacy Enhanced Mail (PEM) file which - contains the corresponding X.509 client certificate - needed to established two-way SSL connection with - the identity service. (optional) - :param string key: Path to the Privacy Enhanced Mail (PEM) file which - contains the unencrypted client private key needed - to established two-way SSL connection with the - identity service. (optional) - :param string cacert: Path to the Privacy Enhanced Mail (PEM) file which - contains the trusted authority X.509 certificates - needed to established SSL connection with the - identity service. (optional) - :param boolean insecure: Does not perform X.509 certificate validation - when establishing SSL connection with identity - service. default: False (optional) - :param dict auth_ref: To allow for consumers of the client to manage their - own caching strategy, you may initialize a client - with a previously captured auth_reference (token) - :param boolean debug: Enables debug logging of all request and responses - to keystone. default False (option) - - .. warning:: - - If debug is enabled, it may show passwords in plain text as a part of - its output. - - .. warning:: - - Constructing an instance of this class without a session is - deprecated as of the 1.7.0 release and will be removed in the - 2.0.0 release. - - The client can be created and used like a user or in a strictly - bootstrap mode. Normal operation expects a username, password, auth_url, - and tenant_name or id to be provided. Other values will be lazily loaded - as needed from the service catalog. - - Example:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> auth = v2.Password(auth_url=KEYSTONE_URL, - ... username=USER, - ... password=PASS, - ... tenant_name=TENANT_NAME) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.tenants.list() - ... - >>> user = keystone.users.get(USER_ID) - >>> user.delete() - - Once authenticated, you can store and attempt to re-use the - authenticated token. the auth_ref property on the client - returns as a dictionary-like-object so that you can export and - cache it, re-using it when initiating another client:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> auth = v2.Password(auth_url=KEYSTONE_URL, - ... username=USER, - ... password=PASS, - ... tenant_name=TENANT_NAME) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> auth_ref = keystone.auth_ref - >>> # pickle or whatever you like here - >>> new_client = client.Client(auth_ref=auth_ref) - - Alternatively, you can provide the administrative token configured in - keystone and an endpoint to communicate with directly. See - (``admin_token`` in ``keystone.conf``) In this case, authenticate() - is not needed, and no service catalog will be loaded. - - Example:: - - >>> from keystoneauth1.identity import v2 - >>> from keystoneauth1 import session - >>> from keystoneclient.v2_0 import client - >>> auth = v2.Token(auth_url='http://localhost:35357/v2.0', - ... token='12345secret7890') - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.tenants.list() - - """ - - version = 'v2.0' - - def __init__(self, **kwargs): - """Initialize a new client for the Keystone v2.0 API.""" - if not kwargs.get('session'): - warnings.warn( - 'Constructing an instance of the ' - 'keystoneclient.v2_0.client.Client class without a session is ' - 'deprecated as of the 1.7.0 release and may be removed in ' - 'the 2.0.0 release.', DeprecationWarning) - - super(Client, self).__init__(**kwargs) - - self.certificates = certificates.CertificatesManager(self._adapter) - self.endpoints = endpoints.EndpointManager(self._adapter) - self.extensions = extensions.ExtensionManager(self._adapter) - self.roles = roles.RoleManager(self._adapter) - self.services = services.ServiceManager(self._adapter) - self.tokens = tokens.TokenManager(self._adapter) - self.users = users.UserManager(self._adapter, self.roles) - - self.tenants = tenants.TenantManager(self._adapter, - self.roles, self.users) - - # extensions - self.ec2 = ec2.CredentialsManager(self._adapter) - - # DEPRECATED: if session is passed then we go to the new behaviour of - # authenticating on the first required call. - if not kwargs.get('session') and self.management_url is None: - self.authenticate() - - def get_raw_token_from_identity_service(self, auth_url, username=None, - password=None, tenant_name=None, - tenant_id=None, token=None, - project_name=None, project_id=None, - trust_id=None, - **kwargs): - """Authenticate against the v2 Identity API. - - If a token is provided it will be used in preference over username and - password. - - :returns: access.AccessInfo if authentication was successful. - :raises keystoneclient.exceptions.AuthorizationFailure: if unable to - authenticate or validate the existing authorization token - """ - try: - if auth_url is None: - raise ValueError(_("Cannot authenticate without an auth_url")) - - new_kwargs = {'trust_id': trust_id, - 'tenant_id': project_id or tenant_id, - 'tenant_name': project_name or tenant_name} - - if token: - plugin = v2_auth.Token(auth_url, token, **new_kwargs) - elif username and password: - plugin = v2_auth.Password(auth_url, username, password, - **new_kwargs) - else: - msg = _('A username and password or token is required.') - raise exceptions.AuthorizationFailure(msg) - - return plugin.get_auth_ref(self.session) - except (exceptions.AuthorizationFailure, exceptions.Unauthorized): - _logger.debug("Authorization Failed.") - raise - except exceptions.EndpointNotFound: - msg = ( - _('There was no suitable authentication url for this request')) - raise exceptions.AuthorizationFailure(msg) - except Exception as e: - raise exceptions.AuthorizationFailure( - _("Authorization Failed: %s") % e) diff --git a/keystoneclient/v2_0/ec2.py b/keystoneclient/v2_0/ec2.py deleted file mode 100644 index 0abe98b0..00000000 --- a/keystoneclient/v2_0/ec2.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class EC2(base.Resource): - def __repr__(self): - """Return string representation of EC2 resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - -class CredentialsManager(base.ManagerWithFind): - resource_class = EC2 - - def create(self, user_id, tenant_id): - """Create a new access/secret pair for the user/tenant pair. - - :rtype: object of type :class:`EC2` - """ - params = {'tenant_id': tenant_id} - - return self._post('/users/%s/credentials/OS-EC2' % user_id, - params, "credential") - - def list(self, user_id): - """Get a list of access/secret pairs for a user_id. - - :rtype: list of :class:`EC2` - """ - return self._list("/users/%s/credentials/OS-EC2" % user_id, - "credentials") - - def get(self, user_id, access): - """Get the access/secret pair for a given access key. - - :rtype: object of type :class:`EC2` - """ - return self._get("/users/%s/credentials/OS-EC2/%s" % - (user_id, base.getid(access)), "credential") - - def delete(self, user_id, access): - """Delete an access/secret pair for a user.""" - return self._delete("/users/%s/credentials/OS-EC2/%s" % - (user_id, base.getid(access))) diff --git a/keystoneclient/v2_0/endpoints.py b/keystoneclient/v2_0/endpoints.py deleted file mode 100644 index 13ac399d..00000000 --- a/keystoneclient/v2_0/endpoints.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2012 Canonical Ltd. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class Endpoint(base.Resource): - """Represents a Keystone endpoint.""" - - def __repr__(self): - """Return string representation of endpoint resource information.""" - return "" % self._info - - -class EndpointManager(base.ManagerWithFind): - """Manager class for manipulating Keystone endpoints.""" - - resource_class = Endpoint - - def list(self): - """List all available endpoints.""" - return self._list('/endpoints', 'endpoints') - - def create(self, region, service_id, publicurl, adminurl=None, - internalurl=None): - """Create a new endpoint.""" - body = {'endpoint': {'region': region, - 'service_id': service_id, - 'publicurl': publicurl, - 'adminurl': adminurl, - 'internalurl': internalurl}} - return self._post('/endpoints', body, 'endpoint') - - def delete(self, id): - """Delete an endpoint.""" - return self._delete('/endpoints/%s' % id) diff --git a/keystoneclient/v2_0/extensions.py b/keystoneclient/v2_0/extensions.py deleted file mode 100644 index f1c40270..00000000 --- a/keystoneclient/v2_0/extensions.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class Extension(base.Resource): - """Represents an Identity API extension.""" - - def __repr__(self): - """Return string representation of extension resource information.""" - return "" % self._info - - -class ExtensionManager(base.ManagerWithFind): - """Manager class for listing Identity API extensions.""" - - resource_class = Extension - - def list(self): - """List all available extensions.""" - return self._list('/extensions', 'extensions') diff --git a/keystoneclient/v2_0/roles.py b/keystoneclient/v2_0/roles.py deleted file mode 100644 index b9180844..00000000 --- a/keystoneclient/v2_0/roles.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class Role(base.Resource): - """Represents a Keystone role.""" - - def __repr__(self): - """Return string representation of role resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - -class RoleManager(base.ManagerWithFind): - """Manager class for manipulating Keystone roles.""" - - resource_class = Role - - def get(self, role): - return self._get("/OS-KSADM/roles/%s" % base.getid(role), "role") - - def create(self, name): - """Create a role.""" - params = {"role": {"name": name}} - return self._post('/OS-KSADM/roles', params, "role") - - def delete(self, role): - """Delete a role.""" - return self._delete("/OS-KSADM/roles/%s" % base.getid(role)) - - def list(self): - """List all available roles.""" - return self._list("/OS-KSADM/roles", "roles") - - def roles_for_user(self, user, tenant=None): - user_id = base.getid(user) - if tenant: - tenant_id = base.getid(tenant) - route = "/tenants/%s/users/%s/roles" - return self._list(route % (tenant_id, user_id), "roles") - else: - return self._list("/users/%s/roles" % user_id, "roles") - - def add_user_role(self, user, role, tenant=None): - """Add a role to a user. - - If tenant is specified, the role is added just for that tenant, - otherwise the role is added globally. - """ - user_id = base.getid(user) - role_id = base.getid(role) - if tenant: - route = "/tenants/%s/users/%s/roles/OS-KSADM/%s" - params = (base.getid(tenant), user_id, role_id) - return self._update(route % params, None, "role") - else: - route = "/users/%s/roles/OS-KSADM/%s" - return self._update(route % (user_id, role_id), None, "roles") - - def remove_user_role(self, user, role, tenant=None): - """Remove a role from a user. - - If tenant is specified, the role is removed just for that tenant, - otherwise the role is removed from the user's global roles. - """ - user_id = base.getid(user) - role_id = base.getid(role) - if tenant: - route = "/tenants/%s/users/%s/roles/OS-KSADM/%s" - params = (base.getid(tenant), user_id, role_id) - return self._delete(route % params) - else: - route = "/users/%s/roles/OS-KSADM/%s" - return self._delete(route % (user_id, role_id)) diff --git a/keystoneclient/v2_0/services.py b/keystoneclient/v2_0/services.py deleted file mode 100644 index 8f20b4da..00000000 --- a/keystoneclient/v2_0/services.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class Service(base.Resource): - """Represents a Keystone service.""" - - def __repr__(self): - """Return string representation of service resource information.""" - return "" % self._info - - -class ServiceManager(base.ManagerWithFind): - """Manager class for manipulating Keystone services.""" - - resource_class = Service - - def list(self): - """List available services.""" - return self._list("/OS-KSADM/services", "OS-KSADM:services") - - def get(self, id): - """Retrieve a service by id.""" - return self._get("/OS-KSADM/services/%s" % id, "OS-KSADM:service") - - def create(self, name, service_type, description=None): - """Create a new service.""" - body = {"OS-KSADM:service": {'name': name, - 'type': service_type, - 'description': description}} - return self._post("/OS-KSADM/services", body, "OS-KSADM:service") - - def delete(self, id): - """Delete a service.""" - return self._delete("/OS-KSADM/services/%s" % id) diff --git a/keystoneclient/v2_0/tenants.py b/keystoneclient/v2_0/tenants.py deleted file mode 100644 index 1b43990d..00000000 --- a/keystoneclient/v2_0/tenants.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1 import plugin -from six.moves import urllib - -from keystoneclient import base -from keystoneclient import exceptions - - -class Tenant(base.Resource): - """Represents a Keystone tenant. - - Attributes: - * id: a uuid that identifies the tenant - * name: tenant name - * description: tenant description - * enabled: boolean to indicate if tenant is enabled - - """ - - def __repr__(self): - """Return string representation of tenant resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - def update(self, name=None, description=None, enabled=None): - # Preserve the existing settings; keystone legacy resets these? - new_name = name if name else self.name - if description is not None: - new_description = description - else: - new_description = self.description - new_enabled = enabled if enabled is not None else self.enabled - - try: - retval = self.manager.update(self.id, tenant_name=new_name, - description=new_description, - enabled=new_enabled) - self = retval - except Exception: - retval = None - return retval - - def add_user(self, user, role): - return self.manager.role_manager.add_user_role(base.getid(user), - base.getid(role), - self.id) - - def remove_user(self, user, role): - return self.manager.role_manager.remove_user_role(base.getid(user), - base.getid(role), - self.id) - - def list_users(self): - return self.manager.list_users(self.id) - - -class TenantManager(base.ManagerWithFind): - """Manager class for manipulating Keystone tenants.""" - - resource_class = Tenant - - def __init__(self, client, role_manager, user_manager): - super(TenantManager, self).__init__(client) - self.role_manager = role_manager - self.user_manager = user_manager - - def get(self, tenant_id): - return self._get("/tenants/%s" % tenant_id, "tenant") - - def create(self, tenant_name, description=None, enabled=True, **kwargs): - """Create a new tenant.""" - params = {"tenant": {"name": tenant_name, - "description": description, - "enabled": enabled}} - - # Allow Extras Passthru and ensure we don't clobber primary arguments. - for k, v in kwargs.items(): - if k not in params['tenant']: - params['tenant'][k] = v - - return self._post('/tenants', params, "tenant") - - def list(self, limit=None, marker=None): - """Get a list of tenants. - - :param integer limit: maximum number to return. (optional) - :param string marker: use when specifying a limit and making - multiple calls for querying. (optional) - - :rtype: list of :class:`Tenant` - - """ - params = {} - if limit: - params['limit'] = limit - if marker: - params['marker'] = marker - - query = "" - if params: - query = "?" + urllib.parse.urlencode(params) - - # NOTE(jamielennox): try doing a regular admin query first. If there is - # no endpoint that can satisfy the request (eg an unscoped token) then - # issue it against the auth_url. - try: - tenant_list = self._list('/tenants%s' % query, 'tenants') - except exceptions.EndpointNotFound: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - tenant_list = self._list('/tenants%s' % query, 'tenants', - endpoint_filter=endpoint_filter) - - return tenant_list - - def update(self, tenant_id, tenant_name=None, description=None, - enabled=None, **kwargs): - """Update a tenant with a new name and description.""" - body = {"tenant": {'id': tenant_id}} - if tenant_name is not None: - body['tenant']['name'] = tenant_name - if enabled is not None: - body['tenant']['enabled'] = enabled - if description is not None: - body['tenant']['description'] = description - - # Allow Extras Passthru and ensure we don't clobber primary arguments. - for k, v in kwargs.items(): - if k not in body['tenant']: - body['tenant'][k] = v - - # Keystone's API uses a POST rather than a PUT here. - return self._post("/tenants/%s" % tenant_id, body, "tenant") - - def delete(self, tenant): - """Delete a tenant.""" - return self._delete("/tenants/%s" % (base.getid(tenant))) - - def list_users(self, tenant): - """List users for a tenant.""" - return self.user_manager.list(base.getid(tenant)) - - def add_user(self, tenant, user, role): - """Add a user to a tenant with the given role.""" - return self.role_manager.add_user_role(base.getid(user), - base.getid(role), - base.getid(tenant)) - - def remove_user(self, tenant, user, role): - """Remove the specified role from the user on the tenant.""" - return self.role_manager.remove_user_role(base.getid(user), - base.getid(role), - base.getid(tenant)) diff --git a/keystoneclient/v2_0/tokens.py b/keystoneclient/v2_0/tokens.py deleted file mode 100644 index 8e647966..00000000 --- a/keystoneclient/v2_0/tokens.py +++ /dev/null @@ -1,127 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1 import exceptions -from keystoneauth1 import plugin -from positional import positional - -from keystoneclient import access -from keystoneclient import base -from keystoneclient.i18n import _ - - -class Token(base.Resource): - def __repr__(self): - """Return string representation of resource information.""" - return "" % self._info - - @property - def id(self): - return self._info['token']['id'] - - @property - def expires(self): - return self._info['token']['expires'] - - @property - def tenant(self): - return self._info['token'].get('tenant') - - -class TokenManager(base.Manager): - resource_class = Token - - @positional(enforcement=positional.WARN) - def authenticate(self, username=None, tenant_id=None, tenant_name=None, - password=None, token=None, return_raw=False): - if token: - params = {"auth": {"token": {"id": token}}} - elif username and password: - params = {"auth": {"passwordCredentials": {"username": username, - "password": password}}} - else: - raise ValueError( - _('A username and password or token is required.')) - if tenant_id: - params['auth']['tenantId'] = tenant_id - elif tenant_name: - params['auth']['tenantName'] = tenant_name - - args = ['/tokens', params, 'access'] - kwargs = {'return_raw': return_raw, 'log': False} - - # NOTE(jamielennox): try doing a regular admin query first. If there is - # no endpoint that can satisfy the request (eg an unscoped token) then - # issue it against the auth_url. - try: - token_ref = self._post(*args, **kwargs) - except exceptions.EndpointNotFound: - kwargs['endpoint_filter'] = {'interface': plugin.AUTH_INTERFACE} - token_ref = self._post(*args, **kwargs) - - return token_ref - - def delete(self, token): - return self._delete("/tokens/%s" % base.getid(token)) - - def endpoints(self, token): - return self._get("/tokens/%s/endpoints" % base.getid(token), "token") - - def validate(self, token): - """Validate a token. - - :param token: Token to be validated. - - :rtype: :py:class:`.Token` - - """ - return self._get('/tokens/%s' % base.getid(token), 'access') - - def get_token_data(self, token): - """Fetch the data about a token from the identity server. - - :param str token: The token id. - - :rtype: dict - """ - url = '/tokens/%s' % token - resp, body = self.client.get(url) - return body - - def validate_access_info(self, token): - """Validate a token. - - :param token: Token to be validated. This can be an instance of - :py:class:`keystoneclient.access.AccessInfo` or a string - token_id. - - :rtype: :py:class:`keystoneclient.access.AccessInfoV2` - - """ - def calc_id(token): - if isinstance(token, access.AccessInfo): - return token.auth_token - return base.getid(token) - - token_id = calc_id(token) - body = self.get_token_data(token_id) - return access.AccessInfo.factory(auth_token=token_id, body=body) - - def get_revoked(self): - """Return the revoked tokens response. - - The response will be a dict containing 'signed' which is a CMS-encoded - document. - - """ - resp, body = self.client.get('/tokens/revoked') - return body diff --git a/keystoneclient/v2_0/users.py b/keystoneclient/v2_0/users.py deleted file mode 100644 index f663626a..00000000 --- a/keystoneclient/v2_0/users.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from six.moves import urllib - -from keystoneclient import base - - -class User(base.Resource): - """Represents a Keystone user.""" - - def __repr__(self): - """Return string representation of user resource information.""" - return "" % self._info - - def delete(self): - return self.manager.delete(self) - - def list_roles(self, tenant=None): - return self.manager.list_roles(self.id, base.getid(tenant)) - - -class UserManager(base.ManagerWithFind): - """Manager class for manipulating Keystone users.""" - - resource_class = User - - def __init__(self, client, role_manager): - super(UserManager, self).__init__(client) - self.role_manager = role_manager - - def get(self, user): - return self._get("/users/%s" % base.getid(user), "user") - - def update(self, user, **kwargs): - """Update user data. - - Supported arguments include ``name``, ``email``, and ``enabled``. - """ - # FIXME(gabriel): "tenantId" seems to be accepted by the API but - # fails to actually update the default tenant. - params = {"user": kwargs} - url = "/users/%s" % base.getid(user) - return self._update(url, params, "user") - - def update_enabled(self, user, enabled): - """Update enabled-ness.""" - params = {"user": {"enabled": enabled}} - - self._update("/users/%s/OS-KSADM/enabled" % base.getid(user), params, - "user") - - def update_password(self, user, password): - """Update password.""" - params = {"user": {"password": password}} - - return self._update("/users/%s/OS-KSADM/password" % base.getid(user), - params, "user", log=False) - - def update_own_password(self, origpasswd, passwd): - """Update password.""" - params = {"user": {"password": passwd, - "original_password": origpasswd}} - - return self._update("/OS-KSCRUD/users/%s" % self.client.user_id, - params, - response_key="access", - method="PATCH", - endpoint_filter={'interface': 'public'}, - log=False) - - def update_tenant(self, user, tenant): - """Update default tenant.""" - params = {"user": {"tenantId": base.getid(tenant)}} - - # FIXME(ja): seems like a bad url - default tenant is an attribute - # not a subresource!??? - return self._update("/users/%s/OS-KSADM/tenant" % base.getid(user), - params, "user") - - def create(self, name, password=None, email=None, - tenant_id=None, enabled=True): - """Create a user.""" - params = {"user": {"name": name, - "password": password, - "tenantId": tenant_id, - "email": email, - "enabled": enabled}} - return self._post('/users', params, "user", log=not bool(password)) - - def delete(self, user): - """Delete a user.""" - return self._delete("/users/%s" % base.getid(user)) - - def list(self, tenant_id=None, limit=None, marker=None): - """Get a list of users (optionally limited to a tenant). - - :rtype: list of :class:`User` - """ - params = {} - if limit: - params['limit'] = int(limit) - if marker: - params['marker'] = marker - - query = "" - if params: - query = "?" + urllib.parse.urlencode(params) - - if not tenant_id: - return self._list("/users%s" % query, "users") - else: - return self._list("/tenants/%s/users%s" % (tenant_id, query), - "users") - - def list_roles(self, user, tenant=None): - return self.role_manager.roles_for_user(base.getid(user), - base.getid(tenant)) diff --git a/keystoneclient/v3/__init__.py b/keystoneclient/v3/__init__.py deleted file mode 100644 index fcb00e06..00000000 --- a/keystoneclient/v3/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ - -from keystoneclient.v3.client import Client # noqa - - -__all__ = ( - 'client', -) diff --git a/keystoneclient/v3/auth.py b/keystoneclient/v3/auth.py deleted file mode 100644 index 6b8d6e9d..00000000 --- a/keystoneclient/v3/auth.py +++ /dev/null @@ -1,69 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1 import exceptions -from keystoneauth1 import plugin - -from keystoneclient import base -from keystoneclient.v3 import domains -from keystoneclient.v3 import projects - - -Domain = domains.Domain -Project = projects.Project - - -class AuthManager(base.Manager): - """Retrieve auth context specific information. - - The information returned by the auth routes is entirely dependent on the - authentication information provided by the user. - """ - - _PROJECTS_URL = '/auth/projects' - _DOMAINS_URL = '/auth/domains' - - def projects(self): - """List projects that the specified token can be rescoped to. - - :returns: a list of projects. - :rtype: list of :class:`keystoneclient.v3.projects.Project` - - """ - try: - return self._list(self._PROJECTS_URL, - 'projects', - obj_class=Project) - except exceptions.EndpointNotFound: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - return self._list(self._PROJECTS_URL, - 'projects', - obj_class=Project, - endpoint_filter=endpoint_filter) - - def domains(self): - """List Domains that the specified token can be rescoped to. - - :returns: a list of domains. - :rtype: list of :class:`keystoneclient.v3.domains.Domain`. - - """ - try: - return self._list(self._DOMAINS_URL, - 'domains', - obj_class=Domain) - except exceptions.EndpointNotFound: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - return self._list(self._DOMAINS_URL, - 'domains', - obj_class=Domain, - endpoint_filter=endpoint_filter) diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py deleted file mode 100644 index 2ca180a7..00000000 --- a/keystoneclient/v3/client.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import warnings - -from oslo_serialization import jsonutils - -from keystoneclient.auth.identity import v3 as v3_auth -from keystoneclient import exceptions -from keystoneclient import httpclient -from keystoneclient.i18n import _ -from keystoneclient.v3 import auth -from keystoneclient.v3.contrib import endpoint_filter -from keystoneclient.v3.contrib import endpoint_policy -from keystoneclient.v3.contrib import federation -from keystoneclient.v3.contrib import oauth1 -from keystoneclient.v3.contrib import simple_cert -from keystoneclient.v3.contrib import trusts -from keystoneclient.v3 import credentials -from keystoneclient.v3 import domain_configs -from keystoneclient.v3 import domains -from keystoneclient.v3 import ec2 -from keystoneclient.v3 import endpoint_groups -from keystoneclient.v3 import endpoints -from keystoneclient.v3 import groups -from keystoneclient.v3 import policies -from keystoneclient.v3 import projects -from keystoneclient.v3 import regions -from keystoneclient.v3 import role_assignments -from keystoneclient.v3 import roles -from keystoneclient.v3 import services -from keystoneclient.v3 import tokens -from keystoneclient.v3 import users - - -_logger = logging.getLogger(__name__) - - -class Client(httpclient.HTTPClient): - r"""Client for the OpenStack Identity API v3. - - :param session: Session for requests. (optional) - :type session: keystoneauth1.session.Session - :param string user_id: User ID for authentication. (optional) - :param string username: Username for authentication. (optional) - :param string user_domain_id: User's domain ID for authentication. - (optional) - :param string user_domain_name: User's domain name for authentication. - (optional) - :param string password: Password for authentication. (optional) - :param string token: Token for authentication. (optional) - :param string domain_id: Domain ID for domain scoping. (optional) - :param string domain_name: Domain name for domain scoping. (optional) - :param string project_id: Project ID for project scoping. (optional) - :param string project_name: Project name for project scoping. (optional) - :param string project_domain_id: Project's domain ID for project - scoping. (optional) - :param string project_domain_name: Project's domain name for project - scoping. (optional) - :param string tenant_name: Tenant name. (optional) - The tenant_name keyword argument is deprecated - as of the 1.7.0 release in favor of project_name - and may be removed in the 2.0.0 release. - :param string tenant_id: Tenant id. (optional) - The tenant_id keyword argument is deprecated as of - the 1.7.0 release in favor of project_id and may - be removed in the 2.0.0 release. - :param string auth_url: Identity service endpoint for authorization. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - :param string endpoint: A user-supplied endpoint URL for the identity - service. Lazy-authentication is possible for API - service calls if endpoint is set at - instantiation. (optional) - :param integer timeout: Allows customization of the timeout for client - http requests. (optional) - - .. warning:: - - Constructing an instance of this class without a session is - deprecated as of the 1.7.0 release and will be removed in the - 2.0.0 release. - - Example:: - - >>> from keystoneauth1.identity import v3 - >>> from keystoneauth1 import session - >>> from keystoneclient.v3 import client - >>> auth = v3.Password(user_domain_name=DOMAIN_NAME, - ... username=USER, - ... password=PASS, - ... project_domain_name=PROJECT_DOMAIN_NAME, - ... project_name=PROJECT_NAME, - ... auth_url=KEYSTONE_URL) - >>> sess = session.Session(auth=auth) - >>> keystone = client.Client(session=sess) - >>> keystone.projects.list() - ... - >>> user = keystone.users.get(USER_ID) - >>> user.delete() - - Instances of this class have the following managers: - - .. py:attribute:: credentials - - :py:class:`keystoneclient.v3.credentials.CredentialManager` - - .. py:attribute:: domain_configs - - :py:class:`keystoneclient.v3.domain_configs.DomainConfigManager` - - .. py:attribute:: ec2 - - :py:class:`keystoneclient.v3.ec2.EC2Manager` - - .. py:attribute:: endpoint_filter - - :py:class:`keystoneclient.v3.contrib.endpoint_filter.\ - EndpointFilterManager` - - .. py:attribute:: endpoint_groups - - :py:class:`keystoneclient.v3.endpoint_groups.\ - EndpointGroupManager` - - .. py:attribute:: endpoint_policy - - :py:class:`keystoneclient.v3.contrib.endpoint_policy.\ - EndpointPolicyManager` - - .. py:attribute:: endpoints - - :py:class:`keystoneclient.v3.endpoints.EndpointManager` - - .. py:attribute:: domains - - :py:class:`keystoneclient.v3.domains.DomainManager` - - .. py:attribute:: federation - - :py:class:`keystoneclient.v3.contrib.federation.core.FederationManager` - - .. py:attribute:: groups - - :py:class:`keystoneclient.v3.groups.GroupManager` - - .. py:attribute:: oauth1 - - :py:class:`keystoneclient.v3.contrib.oauth1.core.OAuthManager` - - .. py:attribute:: policies - - :py:class:`keystoneclient.v3.policies.PolicyManager` - - .. py:attribute:: regions - - :py:class:`keystoneclient.v3.regions.RegionManager` - - .. py:attribute:: role_assignments - - :py:class:`keystoneclient.v3.role_assignments.RoleAssignmentManager` - - .. py:attribute:: roles - - :py:class:`keystoneclient.v3.roles.RoleManager` - - .. py:attribute:: simple_cert - - :py:class:`keystoneclient.v3.contrib.simple_cert.SimpleCertManager` - - .. py:attribute:: services - - :py:class:`keystoneclient.v3.services.ServiceManager` - - .. py:attribute:: tokens - - :py:class:`keystoneclient.v3.tokens.TokenManager` - - .. py:attribute:: trusts - - :py:class:`keystoneclient.v3.contrib.trusts.TrustManager` - - .. py:attribute:: users - - :py:class:`keystoneclient.v3.users.UserManager` - - """ - - version = 'v3' - - def __init__(self, **kwargs): - """Initialize a new client for the Keystone v3 API.""" - super(Client, self).__init__(**kwargs) - - if not kwargs.get('session'): - warnings.warn( - 'Constructing an instance of the ' - 'keystoneclient.v3.client.Client class without a session is ' - 'deprecated as of the 1.7.0 release and may be removed in ' - 'the 2.0.0 release.', DeprecationWarning) - - self.auth = auth.AuthManager(self._adapter) - self.credentials = credentials.CredentialManager(self._adapter) - self.ec2 = ec2.EC2Manager(self._adapter) - self.endpoint_filter = endpoint_filter.EndpointFilterManager( - self._adapter) - self.endpoint_groups = endpoint_groups.EndpointGroupManager( - self._adapter) - self.endpoint_policy = endpoint_policy.EndpointPolicyManager( - self._adapter) - self.endpoints = endpoints.EndpointManager(self._adapter) - self.domain_configs = domain_configs.DomainConfigManager(self._adapter) - self.domains = domains.DomainManager(self._adapter) - self.federation = federation.FederationManager(self._adapter) - self.groups = groups.GroupManager(self._adapter) - self.oauth1 = oauth1.create_oauth_manager(self._adapter) - self.policies = policies.PolicyManager(self._adapter) - self.projects = projects.ProjectManager(self._adapter) - self.regions = regions.RegionManager(self._adapter) - self.role_assignments = ( - role_assignments.RoleAssignmentManager(self._adapter)) - self.roles = roles.RoleManager(self._adapter) - self.inference_rules = roles.InferenceRuleManager(self._adapter) - self.services = services.ServiceManager(self._adapter) - self.simple_cert = simple_cert.SimpleCertManager(self._adapter) - self.tokens = tokens.TokenManager(self._adapter) - self.trusts = trusts.TrustManager(self._adapter) - self.users = users.UserManager(self._adapter) - - # DEPRECATED: if session is passed then we go to the new behaviour of - # authenticating on the first required call. - if 'session' not in kwargs and self.management_url is None: - self.authenticate() - - def serialize(self, entity): - return jsonutils.dumps(entity, sort_keys=True) - - def process_token(self, **kwargs): - """Extract and process information from the new auth_ref. - - And set the relevant authentication information. - """ - super(Client, self).process_token(**kwargs) - if self.auth_ref.domain_scoped: - if not self.auth_ref.domain_id: - raise exceptions.AuthorizationFailure( - _("Token didn't provide domain_id")) - self._process_management_url(kwargs.get('region_name')) - self.domain_name = self.auth_ref.domain_name - self.domain_id = self.auth_ref.domain_id - if self._management_url: - self._management_url = self._management_url.replace('/v2.0', '/v3') - - def get_raw_token_from_identity_service(self, auth_url, user_id=None, - username=None, - user_domain_id=None, - user_domain_name=None, - password=None, - domain_id=None, domain_name=None, - project_id=None, project_name=None, - project_domain_id=None, - project_domain_name=None, - token=None, - trust_id=None, - **kwargs): - """Authenticate against the v3 Identity API. - - If password and token methods are both provided then both methods will - be used in the request. - - :returns: access.AccessInfo if authentication was successful. - :rtype: :class:`keystoneclient.access.AccessInfoV3` - :raises keystoneclient.exceptions.AuthorizationFailure: if unable to - authenticate or validate the existing authorization token. - :raises keystoneclient.exceptions.Unauthorized: if authentication fails - due to invalid token. - - """ - try: - if auth_url is None: - raise ValueError(_("Cannot authenticate without an auth_url")) - - auth_methods = [] - - if token: - auth_methods.append(v3_auth.TokenMethod(token=token)) - - if password: - m = v3_auth.PasswordMethod(user_id=user_id, - username=username, - user_domain_id=user_domain_id, - user_domain_name=user_domain_name, - password=password) - auth_methods.append(m) - - if not auth_methods: - msg = _('A user and password or token is required.') - raise exceptions.AuthorizationFailure(msg) - - plugin = v3_auth.Auth(auth_url, auth_methods, - trust_id=trust_id, - domain_id=domain_id, - domain_name=domain_name, - project_id=project_id, - project_name=project_name, - project_domain_id=project_domain_id, - project_domain_name=project_domain_name) - - return plugin.get_auth_ref(self.session) - except (exceptions.AuthorizationFailure, exceptions.Unauthorized): - _logger.debug('Authorization failed.') - raise - except exceptions.EndpointNotFound: - msg = _('There was no suitable authentication url for this' - ' request') - raise exceptions.AuthorizationFailure(msg) - except Exception as e: - raise exceptions.AuthorizationFailure( - _('Authorization failed: %s') % e) diff --git a/keystoneclient/v3/contrib/__init__.py b/keystoneclient/v3/contrib/__init__.py deleted file mode 100644 index 576bd621..00000000 --- a/keystoneclient/v3/contrib/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -__all__ = tuple() diff --git a/keystoneclient/v3/contrib/endpoint_filter.py b/keystoneclient/v3/contrib/endpoint_filter.py deleted file mode 100644 index 26d5a874..00000000 --- a/keystoneclient/v3/contrib/endpoint_filter.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient.v3 import endpoint_groups -from keystoneclient.v3 import endpoints -from keystoneclient.v3 import projects - - -class EndpointFilterManager(base.Manager): - """Manager class for manipulating project-endpoint associations. - - Project-endpoint associations can be with endpoints directly or via - endpoint groups. - - """ - - OS_EP_FILTER_EXT = '/OS-EP-FILTER' - - def _build_base_url(self, project=None, endpoint=None): - project_id = base.getid(project) - endpoint_id = base.getid(endpoint) - - if project_id and endpoint_id: - api_path = '/projects/%s/endpoints/%s' % (project_id, endpoint_id) - elif project_id: - api_path = '/projects/%s/endpoints' % (project_id) - elif endpoint_id: - api_path = '/endpoints/%s/projects' % (endpoint_id) - else: - msg = _('Must specify a project, an endpoint, or both') - raise exceptions.ValidationError(msg) - - return self.OS_EP_FILTER_EXT + api_path - - def _build_group_base_url(self, project=None, endpoint_group=None): - project_id = base.getid(project) - endpoint_group_id = base.getid(endpoint_group) - - if project_id and endpoint_group_id: - api_path = '/endpoint_groups/%s/projects/%s' % ( - endpoint_group_id, project_id) - elif project_id: - api_path = '/projects/%s/endpoint_groups' % (project_id) - elif endpoint_group_id: - api_path = '/endpoint_groups/%s/projects' % (endpoint_group_id) - else: - msg = _('Must specify a project, an endpoint group, or both') - raise exceptions.ValidationError(msg) - - return self.OS_EP_FILTER_EXT + api_path - - def add_endpoint_to_project(self, project, endpoint): - """Create a project-endpoint association.""" - if not (project and endpoint): - raise ValueError(_('project and endpoint are required')) - - base_url = self._build_base_url(project=project, - endpoint=endpoint) - return super(EndpointFilterManager, self)._put(url=base_url) - - def delete_endpoint_from_project(self, project, endpoint): - """Remove a project-endpoint association.""" - if not (project and endpoint): - raise ValueError(_('project and endpoint are required')) - - base_url = self._build_base_url(project=project, - endpoint=endpoint) - return super(EndpointFilterManager, self)._delete(url=base_url) - - def check_endpoint_in_project(self, project, endpoint): - """Check if project-endpoint association exists.""" - if not (project and endpoint): - raise ValueError(_('project and endpoint are required')) - - base_url = self._build_base_url(project=project, - endpoint=endpoint) - return super(EndpointFilterManager, self)._head(url=base_url) - - def list_endpoints_for_project(self, project): - """List all endpoints for a given project.""" - if not project: - raise ValueError(_('project is required')) - - base_url = self._build_base_url(project=project) - return super(EndpointFilterManager, self)._list( - base_url, - endpoints.EndpointManager.collection_key, - obj_class=endpoints.EndpointManager.resource_class) - - def list_projects_for_endpoint(self, endpoint): - """List all projects for a given endpoint.""" - if not endpoint: - raise ValueError(_('endpoint is required')) - - base_url = self._build_base_url(endpoint=endpoint) - return super(EndpointFilterManager, self)._list( - base_url, - projects.ProjectManager.collection_key, - obj_class=projects.ProjectManager.resource_class) - - def add_endpoint_group_to_project(self, endpoint_group, project): - """Create a project-endpoint group association.""" - if not (project and endpoint_group): - raise ValueError(_('project and endpoint_group are required')) - - base_url = self._build_group_base_url(project=project, - endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._put(url=base_url) - - def delete_endpoint_group_from_project(self, endpoint_group, project): - """Remove a project-endpoint group association.""" - if not (project and endpoint_group): - raise ValueError(_('project and endpoint_group are required')) - - base_url = self._build_group_base_url(project=project, - endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._delete(url=base_url) - - def check_endpoint_group_in_project(self, endpoint_group, project): - """Check if project-endpoint group association exists.""" - if not (project and endpoint_group): - raise ValueError(_('project and endpoint_group are required')) - - base_url = self._build_group_base_url(project=project, - endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._head(url=base_url) - - def list_endpoint_groups_for_project(self, project): - """List all endpoint groups for a given project.""" - if not project: - raise ValueError(_('project is required')) - - base_url = self._build_group_base_url(project=project) - - return super(EndpointFilterManager, self)._list( - base_url, - 'endpoint_groups', - obj_class=endpoint_groups.EndpointGroupManager.resource_class) - - def list_projects_for_endpoint_group(self, endpoint_group): - """List all projects associated with a given endpoint group.""" - if not endpoint_group: - raise ValueError(_('endpoint_group is required')) - - base_url = self._build_group_base_url(endpoint_group=endpoint_group) - return super(EndpointFilterManager, self)._list( - base_url, - projects.ProjectManager.collection_key, - obj_class=projects.ProjectManager.resource_class) diff --git a/keystoneclient/v3/contrib/endpoint_policy.py b/keystoneclient/v3/contrib/endpoint_policy.py deleted file mode 100644 index 24148c1a..00000000 --- a/keystoneclient/v3/contrib/endpoint_policy.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base -from keystoneclient.i18n import _ -from keystoneclient.v3 import endpoints -from keystoneclient.v3 import policies - - -class EndpointPolicyManager(base.Manager): - """Manager class for manipulating endpoint-policy associations.""" - - OS_EP_POLICY_EXT = 'OS-ENDPOINT-POLICY' - - def _act_on_policy_association_for_endpoint( - self, policy, endpoint, action): - if not (policy and endpoint): - raise ValueError(_('policy and endpoint are required')) - - policy_id = base.getid(policy) - endpoint_id = base.getid(endpoint) - url = ('/policies/%(policy_id)s/%(ext_name)s' - '/endpoints/%(endpoint_id)s') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT, - 'endpoint_id': endpoint_id} - return action(url=url) - - def create_policy_association_for_endpoint(self, policy, endpoint): - """Create an association between a policy and an endpoint.""" - self._act_on_policy_association_for_endpoint( - policy, endpoint, self._put) - - def check_policy_association_for_endpoint(self, policy, endpoint): - """Check an association between a policy and an endpoint.""" - self._act_on_policy_association_for_endpoint( - policy, endpoint, self._head) - - def delete_policy_association_for_endpoint(self, policy, endpoint): - """Delete an association between a policy and an endpoint.""" - self._act_on_policy_association_for_endpoint( - policy, endpoint, self._delete) - - def _act_on_policy_association_for_service(self, policy, service, action): - if not (policy and service): - raise ValueError(_('policy and service are required')) - - policy_id = base.getid(policy) - service_id = base.getid(service) - url = ('/policies/%(policy_id)s/%(ext_name)s' - '/services/%(service_id)s') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT, - 'service_id': service_id} - return action(url=url) - - def create_policy_association_for_service(self, policy, service): - """Create an association between a policy and a service.""" - self._act_on_policy_association_for_service( - policy, service, self._put) - - def check_policy_association_for_service(self, policy, service): - """Check an association between a policy and a service.""" - self._act_on_policy_association_for_service( - policy, service, self._head) - - def delete_policy_association_for_service(self, policy, service): - """Delete an association between a policy and a service.""" - self._act_on_policy_association_for_service( - policy, service, self._delete) - - def _act_on_policy_association_for_region_and_service( - self, policy, region, service, action): - if not (policy and region and service): - raise ValueError(_('policy, region and service are required')) - - policy_id = base.getid(policy) - region_id = base.getid(region) - service_id = base.getid(service) - url = ('/policies/%(policy_id)s/%(ext_name)s' - '/services/%(service_id)s/regions/%(region_id)s') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT, - 'service_id': service_id, - 'region_id': region_id} - return action(url=url) - - def create_policy_association_for_region_and_service( - self, policy, region, service): - """Create an association between a policy and a service in a region.""" - self._act_on_policy_association_for_region_and_service( - policy, region, service, self._put) - - def check_policy_association_for_region_and_service( - self, policy, region, service): - """Check an association between a policy and a service in a region.""" - self._act_on_policy_association_for_region_and_service( - policy, region, service, self._head) - - def delete_policy_association_for_region_and_service( - self, policy, region, service): - """Delete an association between a policy and a service in a region.""" - self._act_on_policy_association_for_region_and_service( - policy, region, service, self._delete) - - def get_policy_for_endpoint(self, endpoint): - """Get the effective policy for an endpoint. - - :param endpoint: endpoint object or ID - - :returns: policies.Policy object - - """ - if not endpoint: - raise ValueError(_('endpoint is required')) - - endpoint_id = base.getid(endpoint) - url = ('/endpoints/%(endpoint_id)s/%(ext_name)s/policy') % { - 'endpoint_id': endpoint_id, - 'ext_name': self.OS_EP_POLICY_EXT} - - _resp, body = self.client.get(url) - return policies.Policy( - self, body[policies.PolicyManager.key], loaded=True) - - def list_endpoints_for_policy(self, policy): - """List endpoints with the effective association to a policy. - - :param policy: policy object or ID - - :returns: list of endpoints that are associated with the policy - - """ - if not policy: - raise ValueError(_('policy is required')) - - policy_id = base.getid(policy) - url = ('/policies/%(policy_id)s/%(ext_name)s/endpoints') % { - 'policy_id': policy_id, - 'ext_name': self.OS_EP_POLICY_EXT} - return self._list( - url, - endpoints.EndpointManager.collection_key, - obj_class=endpoints.EndpointManager.resource_class) diff --git a/keystoneclient/v3/contrib/federation/__init__.py b/keystoneclient/v3/contrib/federation/__init__.py deleted file mode 100644 index ee9bcef9..00000000 --- a/keystoneclient/v3/contrib/federation/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.v3.contrib.federation.core import * # noqa diff --git a/keystoneclient/v3/contrib/federation/base.py b/keystoneclient/v3/contrib/federation/base.py deleted file mode 100644 index 98567a23..00000000 --- a/keystoneclient/v3/contrib/federation/base.py +++ /dev/null @@ -1,40 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from keystoneauth1 import exceptions -from keystoneauth1 import plugin -import six - -from keystoneclient import base - - -@six.add_metaclass(abc.ABCMeta) -class EntityManager(base.Manager): - """Manager class for listing federated accessible objects.""" - - resource_class = None - - @abc.abstractproperty - def object_type(self): - raise exceptions.MethodNotImplemented - - def list(self): - url = '/auth/%s' % self.object_type - try: - tenant_list = self._list(url, self.object_type) - except exceptions.CatalogException: - endpoint_filter = {'interface': plugin.AUTH_INTERFACE} - tenant_list = self._list(url, self.object_type, - endpoint_filter=endpoint_filter) - return tenant_list diff --git a/keystoneclient/v3/contrib/federation/core.py b/keystoneclient/v3/contrib/federation/core.py deleted file mode 100644 index 2e12cf60..00000000 --- a/keystoneclient/v3/contrib/federation/core.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.v3.contrib.federation import domains -from keystoneclient.v3.contrib.federation import identity_providers -from keystoneclient.v3.contrib.federation import mappings -from keystoneclient.v3.contrib.federation import projects -from keystoneclient.v3.contrib.federation import protocols -from keystoneclient.v3.contrib.federation import saml -from keystoneclient.v3.contrib.federation import service_providers - - -class FederationManager(object): - def __init__(self, api): - self.identity_providers = identity_providers.IdentityProviderManager( - api) - self.mappings = mappings.MappingManager(api) - self.protocols = protocols.ProtocolManager(api) - self.projects = projects.ProjectManager(api) - self.domains = domains.DomainManager(api) - self.saml = saml.SamlManager(api) - self.service_providers = service_providers.ServiceProviderManager(api) diff --git a/keystoneclient/v3/contrib/federation/domains.py b/keystoneclient/v3/contrib/federation/domains.py deleted file mode 100644 index 4d5e1353..00000000 --- a/keystoneclient/v3/contrib/federation/domains.py +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.v3.contrib.federation import base as federation_base -from keystoneclient.v3 import domains - - -class DomainManager(federation_base.EntityManager): - object_type = 'domains' - resource_class = domains.Domain diff --git a/keystoneclient/v3/contrib/federation/identity_providers.py b/keystoneclient/v3/contrib/federation/identity_providers.py deleted file mode 100644 index 4675ca36..00000000 --- a/keystoneclient/v3/contrib/federation/identity_providers.py +++ /dev/null @@ -1,113 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class IdentityProvider(base.Resource): - """Object representing Identity Provider container. - - Attributes: - * id: user-defined unique string identifying Identity Provider. - - """ - - pass - - -class IdentityProviderManager(base.CrudManager): - """Manager class for manipulating Identity Providers.""" - - resource_class = IdentityProvider - collection_key = 'identity_providers' - key = 'identity_provider' - base_url = 'OS-FEDERATION' - - def _build_url_and_put(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: kwargs} - return self._update(url, body=body, response_key=self.key, - method='PUT') - - @positional.method(0) - def create(self, id, **kwargs): - """Create Identity Provider object. - - Utilize Keystone URI: - PUT /OS-FEDERATION/identity_providers/$identity_provider - - :param id: unique id of the identity provider. - :param kwargs: optional attributes: description (str), enabled - (boolean) and remote_ids (list). - :returns: an IdentityProvider resource object. - :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` - - """ - return self._build_url_and_put(identity_provider_id=id, - **kwargs) - - def get(self, identity_provider): - """Fetch Identity Provider object. - - Utilize Keystone URI: - GET /OS-FEDERATION/identity_providers/$identity_provider - - :param identity_provider: an object with identity_provider_id - stored inside. - :returns: an IdentityProvider resource object. - :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` - - """ - return super(IdentityProviderManager, self).get( - identity_provider_id=base.getid(identity_provider)) - - def list(self, **kwargs): - """List all Identity Providers. - - Utilize Keystone URI: - GET /OS-FEDERATION/identity_providers - - :returns: a list of IdentityProvider resource objects. - :rtype: List - - """ - return super(IdentityProviderManager, self).list(**kwargs) - - def update(self, identity_provider, **kwargs): - """Update Identity Provider object. - - Utilize Keystone URI: - PATCH /OS-FEDERATION/identity_providers/$identity_provider - - :param identity_provider: an object with identity_provider_id - stored inside. - :returns: an IdentityProvider resource object. - :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` - - """ - return super(IdentityProviderManager, self).update( - identity_provider_id=base.getid(identity_provider), **kwargs) - - def delete(self, identity_provider): - """Delete Identity Provider object. - - Utilize Keystone URI: - DELETE /OS-FEDERATION/identity_providers/$identity_provider - - :param identity_provider: the Identity Provider ID itself or an object - with it stored inside. - - """ - return super(IdentityProviderManager, self).delete( - identity_provider_id=base.getid(identity_provider)) diff --git a/keystoneclient/v3/contrib/federation/mappings.py b/keystoneclient/v3/contrib/federation/mappings.py deleted file mode 100644 index 24a9c7f4..00000000 --- a/keystoneclient/v3/contrib/federation/mappings.py +++ /dev/null @@ -1,153 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Mapping(base.Resource): - """An object representing mapping container. - - Attributes: - * id: user defined unique string identifying mapping. - - """ - - pass - - -class MappingManager(base.CrudManager): - """Manager class for manipulating federation mappings.""" - - resource_class = Mapping - collection_key = 'mappings' - key = 'mapping' - base_url = 'OS-FEDERATION' - - def _build_url_and_put(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: kwargs} - return self._update(url, body=body, - response_key=self.key, - method='PUT') - - @positional.method(0) - def create(self, mapping_id, **kwargs): - """Create federation mapping. - - Utilize Identity API operation: - PUT /OS-FEDERATION/mappings/$mapping_id - - :param mapping_id: user defined string identifier of the federation - mapping. - :param rules: a list of mapping rules. - - Example of the ``rules`` parameter:: - - [ - { - "local": [ - { - "group": { - "id": "0cd5e9" - } - } - ], - "remote": [ - { - "type": "orgPersonType", - "not_any_of": [ - "Contractor", - "Guest" - ] - } - ] - } - ] - - """ - return self._build_url_and_put( - mapping_id=mapping_id, **kwargs) - - def get(self, mapping): - """Fetch federation mapping identified by mapping id. - - Utilize Identity API operation: - GET /OS-FEDERATION/mappings/$mapping_id - - :param mapping: a Mapping type object with mapping id - stored inside. - - """ - return super(MappingManager, self).get( - mapping_id=base.getid(mapping)) - - def list(self, **kwargs): - """List all federation mappings. - - Utilize Identity API operation: - GET /OS-FEDERATION/mappings - - """ - return super(MappingManager, self).list(**kwargs) - - def update(self, mapping, **kwargs): - """Update federation mapping identified by mapping id. - - Utilize Identity API operation: - PATCH /OS-FEDERATION/mappings/$mapping_id - - :param mapping: a Mapping type object with mapping id - stored inside. - :param rules: a list of mapping rules. - - Example of the ``rules`` parameter:: - - - [ - { - "local": [ - { - "group": { - "id": "0cd5e9" - } - } - ], - "remote": [ - { - "type": "orgPersonType", - "not_any_of": [ - "Contractor", - "Guest" - ] - } - ] - } - ] - - """ - return super(MappingManager, self).update( - mapping_id=base.getid(mapping), **kwargs) - - def delete(self, mapping): - """Delete federation mapping identified by mapping id. - - Utilize Identity API operation: - DELETE /OS-FEDERATION/mappings/$mapping_id - - :param mapping: a Mapping type object with mapping id - stored inside. - - """ - return super(MappingManager, self).delete( - mapping_id=base.getid(mapping)) diff --git a/keystoneclient/v3/contrib/federation/projects.py b/keystoneclient/v3/contrib/federation/projects.py deleted file mode 100644 index 8e657b45..00000000 --- a/keystoneclient/v3/contrib/federation/projects.py +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.v3.contrib.federation import base as federation_base -from keystoneclient.v3 import projects - - -class ProjectManager(federation_base.EntityManager): - object_type = 'projects' - resource_class = projects.Project diff --git a/keystoneclient/v3/contrib/federation/protocols.py b/keystoneclient/v3/contrib/federation/protocols.py deleted file mode 100644 index 34daf0f7..00000000 --- a/keystoneclient/v3/contrib/federation/protocols.py +++ /dev/null @@ -1,146 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Protocol(base.Resource): - """An object representing federation protocol container. - - Attributes: - * id: user-defined unique per Identity Provider string identifying - federation protocol. - - """ - - pass - - -class ProtocolManager(base.CrudManager): - """Manager class for manipulating federation protocols.""" - - resource_class = Protocol - collection_key = 'protocols' - key = 'protocol' - base_url = 'OS-FEDERATION/identity_providers' - - def build_url(self, dict_args_in_out=None): - """Build URL for federation protocols.""" - if dict_args_in_out is None: - dict_args_in_out = {} - - identity_provider_id = dict_args_in_out.pop('identity_provider_id', - None) - if identity_provider_id: - base_url = '/'.join([self.base_url, identity_provider_id]) - else: - base_url = self.base_url - - dict_args_in_out.setdefault('base_url', base_url) - return super(ProtocolManager, self).build_url(dict_args_in_out) - - def _build_url_and_put(self, request_body=None, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: request_body} - return self._update(url, body=body, - response_key=self.key, - method='PUT') - - @positional.method(3) - def create(self, protocol_id, identity_provider, mapping, **kwargs): - """Create federation protocol object and tie to the Identity Provider. - - Utilize Identity API operation: - PUT /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param protocol_id: a string type parameter identifying a federation - protocol - :param identity_provider: a string type parameter identifying an - Identity Provider - :param mapping: a base.Resource object with federation mapping id - - """ - return self._build_url_and_put( - request_body={'mapping_id': base.getid(mapping)}, - identity_provider_id=base.getid(identity_provider), - protocol_id=protocol_id, **kwargs) - - def get(self, identity_provider, protocol, **kwargs): - """Fetch federation protocol object tied to the Identity Provider. - - Utilize Identity API operation: - GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param identity_provider: a base.Resource type object with Identity - Provider id stored inside - :param protocol: a base.Resource type object with federation protocol - id stored inside - - """ - return super(ProtocolManager, self).get( - identity_provider_id=base.getid(identity_provider), - protocol_id=base.getid(protocol), **kwargs) - - def list(self, identity_provider, **kwargs): - """List all federation protocol objects tied to the Identity Provider. - - Utilize Identity API operation: - GET /OS-FEDERATION/identity_providers/ - $identity_provider/protocols - - :param identity_provider: a base.Resource type object with Identity - Provider id stored inside - - """ - return super(ProtocolManager, self).list( - identity_provider_id=base.getid(identity_provider), **kwargs) - - def update(self, identity_provider, protocol, mapping, **kwargs): - """Update Protocol object tied to the Identity Provider. - - Utilize Identity API operation: - PATCH /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param identity_provider: a base.Resource type object with Identity - Provider id stored inside - :param protocol: a base.Resource type object with federation protocol - id stored inside - :param mapping: a base.Resource object with federation mapping id - - - """ - return super(ProtocolManager, self).update( - identity_provider_id=base.getid(identity_provider), - protocol_id=base.getid(protocol), mapping_id=base.getid(mapping), - **kwargs) - - def delete(self, identity_provider, protocol): - """Delete Protocol object tied to the Identity Provider. - - Utilize Identity API operation: - DELETE /OS-FEDERATION/identity_providers/ - $identity_provider/protocols/$protocol - - :param identity_provider: a base.Resource type object with - Identity Provider id stored inside - :param protocol: a base.Resource type object with federation - protocol id stored inside - - """ - return super(ProtocolManager, self).delete( - identity_provider_id=base.getid(identity_provider), - protocol_id=base.getid(protocol)) diff --git a/keystoneclient/v3/contrib/federation/saml.py b/keystoneclient/v3/contrib/federation/saml.py deleted file mode 100644 index 9be657a5..00000000 --- a/keystoneclient/v3/contrib/federation/saml.py +++ /dev/null @@ -1,79 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -SAML2_ENDPOINT = '/auth/OS-FEDERATION/saml2' -ECP_ENDPOINT = '/auth/OS-FEDERATION/saml2/ecp' - - -class SamlManager(base.Manager): - """Manager class for creating SAML assertions.""" - - def create_saml_assertion(self, service_provider, token_id): - """Create a SAML assertion from a token. - - Equivalent Identity API call: - POST /auth/OS-FEDERATION/saml2 - - :param service_provider: Service Provider resource. - :type service_provider: string - :param token_id: Token to transform to SAML assertion. - :type token_id: string - - :returns: SAML representation of token_id - :rtype: string - """ - headers, body = self._create_common_request(service_provider, token_id) - resp, body = self.client.post(SAML2_ENDPOINT, json=body, - headers=headers) - return resp.text - - def create_ecp_assertion(self, service_provider, token_id): - """Create an ECP wrapped SAML assertion from a token. - - Equivalent Identity API call: - POST /auth/OS-FEDERATION/saml2/ecp - - :param service_provider: Service Provider resource. - :type service_provider: string - :param token_id: Token to transform to SAML assertion. - :type token_id: string - - :returns: SAML representation of token_id, wrapped in ECP envelope - :rtype: string - """ - headers, body = self._create_common_request(service_provider, token_id) - resp, body = self.client.post(ECP_ENDPOINT, json=body, - headers=headers) - return resp.text - - def _create_common_request(self, service_provider, token_id): - headers = {'Content-Type': 'application/json'} - body = { - 'auth': { - 'identity': { - 'methods': ['token'], - 'token': { - 'id': token_id - } - }, - 'scope': { - 'service_provider': { - 'id': base.getid(service_provider) - } - } - } - } - - return (headers, body) diff --git a/keystoneclient/v3/contrib/federation/service_providers.py b/keystoneclient/v3/contrib/federation/service_providers.py deleted file mode 100644 index f731c394..00000000 --- a/keystoneclient/v3/contrib/federation/service_providers.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class ServiceProvider(base.Resource): - """Object representing Service Provider container. - - Attributes: - * id: user-defined unique string identifying Service Provider. - * sp_url: the shibboleth endpoint of a Service Provider. - * auth_url: the authentication url of Service Provider. - - """ - - pass - - -class ServiceProviderManager(base.CrudManager): - """Manager class for manipulating Service Providers.""" - - resource_class = ServiceProvider - collection_key = 'service_providers' - key = 'service_provider' - base_url = 'OS-FEDERATION' - - def _build_url_and_put(self, **kwargs): - url = self.build_url(dict_args_in_out=kwargs) - body = {self.key: kwargs} - return self._update(url, body=body, response_key=self.key, - method='PUT') - - @positional.method(0) - def create(self, id, **kwargs): - """Create Service Provider object. - - Utilize Keystone URI: - ``PUT /OS-FEDERATION/service_providers/{id}`` - - :param id: unique id of the service provider. - - """ - return self._build_url_and_put(service_provider_id=id, - **kwargs) - - def get(self, service_provider): - """Fetch Service Provider object. - - Utilize Keystone URI: - ``GET /OS-FEDERATION/service_providers/{id}`` - - :param service_provider: an object with service_provider_id - stored inside. - - """ - return super(ServiceProviderManager, self).get( - service_provider_id=base.getid(service_provider)) - - def list(self, **kwargs): - """List all Service Providers. - - Utilize Keystone URI: - ``GET /OS-FEDERATION/service_providers`` - - """ - return super(ServiceProviderManager, self).list(**kwargs) - - def update(self, service_provider, **kwargs): - """Update the existing Service Provider object on the server. - - Only properties provided to the function are being updated. - - Utilize Keystone URI: - ``PATCH /OS-FEDERATION/service_providers/{id}`` - - :param service_provider: an object with service_provider_id - stored inside. - - """ - return super(ServiceProviderManager, self).update( - service_provider_id=base.getid(service_provider), **kwargs) - - def delete(self, service_provider): - """Delete Service Provider object. - - Utilize Keystone URI: - ``DELETE /OS-FEDERATION/service_providers/{id}`` - - :param service_provider: an object with service_provider_id - stored inside. - - """ - return super(ServiceProviderManager, self).delete( - service_provider_id=base.getid(service_provider)) diff --git a/keystoneclient/v3/contrib/oauth1/__init__.py b/keystoneclient/v3/contrib/oauth1/__init__.py deleted file mode 100644 index e1fb8b79..00000000 --- a/keystoneclient/v3/contrib/oauth1/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient.v3.contrib.oauth1.core import * # noqa diff --git a/keystoneclient/v3/contrib/oauth1/access_tokens.py b/keystoneclient/v3/contrib/oauth1/access_tokens.py deleted file mode 100644 index 37f19415..00000000 --- a/keystoneclient/v3/contrib/oauth1/access_tokens.py +++ /dev/null @@ -1,51 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import unicode_literals - -from keystoneauth1 import plugin - -from keystoneclient import base -from keystoneclient.v3.contrib.oauth1 import utils - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class AccessToken(base.Resource): - pass - - -class AccessTokenManager(base.CrudManager): - """Manager class for manipulating identity OAuth access tokens.""" - - resource_class = AccessToken - - def create(self, consumer_key, consumer_secret, request_key, - request_secret, verifier): - endpoint = utils.OAUTH_PATH + '/access_token' - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - resource_owner_key=request_key, - resource_owner_secret=request_secret, - signature_method=oauth1.SIGNATURE_HMAC, - verifier=verifier) - url = self.client.get_endpoint(interface=plugin.AUTH_INTERFACE).rstrip( - '/') - url, headers, body = oauth_client.sign(url + endpoint, - http_method='POST') - resp, body = self.client.post(endpoint, headers=headers) - token = utils.get_oauth_token_from_body(resp.content) - return self.resource_class(self, token) diff --git a/keystoneclient/v3/contrib/oauth1/auth.py b/keystoneclient/v3/contrib/oauth1/auth.py deleted file mode 100644 index bd4a152e..00000000 --- a/keystoneclient/v3/contrib/oauth1/auth.py +++ /dev/null @@ -1,55 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from keystoneclient.auth.identity import v3 - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class OAuthMethod(v3.AuthMethod): - """OAuth based authentication method. - - :param string consumer_key: Consumer key. - :param string consumer_secret: Consumer secret. - :param string access_key: Access token key. - :param string access_secret: Access token secret. - """ - - _method_parameters = ['consumer_key', 'consumer_secret', - 'access_key', 'access_secret'] - - def __init__(self, **kwargs): - super(OAuthMethod, self).__init__(**kwargs) - if oauth1 is None: - raise NotImplementedError('optional package oauthlib' - ' is not installed') - - def get_auth_data(self, session, auth, headers, **kwargs): - # Add the oauth specific content into the headers - oauth_client = oauth1.Client(self.consumer_key, - client_secret=self.consumer_secret, - resource_owner_key=self.access_key, - resource_owner_secret=self.access_secret, - signature_method=oauth1.SIGNATURE_HMAC) - o_url, o_headers, o_body = oauth_client.sign(auth.token_url, - http_method='POST') - - headers.update(o_headers) - return 'oauth1', {} - - -class OAuth(v3.AuthConstructor): - _auth_method_class = OAuthMethod diff --git a/keystoneclient/v3/contrib/oauth1/consumers.py b/keystoneclient/v3/contrib/oauth1/consumers.py deleted file mode 100644 index 5c81ff47..00000000 --- a/keystoneclient/v3/contrib/oauth1/consumers.py +++ /dev/null @@ -1,54 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from keystoneclient import base -from keystoneclient.v3.contrib.oauth1 import utils - - -class Consumer(base.Resource): - """Represents an OAuth consumer. - - Attributes: - * id: a uuid that identifies the consumer - * description: a short description of the consumer - """ - - pass - - -class ConsumerManager(base.CrudManager): - """Manager class for manipulating identity consumers.""" - - resource_class = Consumer - collection_key = 'consumers' - key = 'consumer' - base_url = utils.OAUTH_PATH - - def create(self, description=None, **kwargs): - return super(ConsumerManager, self).create( - description=description, - **kwargs) - - def get(self, consumer): - return super(ConsumerManager, self).get( - consumer_id=base.getid(consumer)) - - def update(self, consumer, description=None, **kwargs): - return super(ConsumerManager, self).update( - consumer_id=base.getid(consumer), - description=description, - **kwargs) - - def delete(self, consumer): - return super(ConsumerManager, self).delete( - consumer_id=base.getid(consumer)) diff --git a/keystoneclient/v3/contrib/oauth1/core.py b/keystoneclient/v3/contrib/oauth1/core.py deleted file mode 100644 index 4b0278e1..00000000 --- a/keystoneclient/v3/contrib/oauth1/core.py +++ /dev/null @@ -1,66 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from keystoneclient.i18n import _ -from keystoneclient.v3.contrib.oauth1 import access_tokens -from keystoneclient.v3.contrib.oauth1 import consumers -from keystoneclient.v3.contrib.oauth1 import request_tokens - - -def create_oauth_manager(self): - # NOTE(stevemar): Attempt to import the oauthlib package at this point. - try: - import oauthlib # noqa - # NOTE(stevemar): Return an object instead of raising an exception here, - # this will allow users to see an exception only when trying to access the - # oauth portions of client. Otherwise an exception would be raised - # when the client is created. - except ImportError: - return OAuthManagerOptionalImportProxy() - else: - return OAuthManager(self) - - -class OAuthManager(object): - def __init__(self, api): - self.access_tokens = access_tokens.AccessTokenManager(api) - self.consumers = consumers.ConsumerManager(api) - self.request_tokens = request_tokens.RequestTokenManager(api) - - -class OAuthManagerOptionalImportProxy(object): - """Act as a proxy manager in case oauthlib is no installed. - - This class will only be created if oauthlib is not in the system, - trying to access any of the attributes in name (access_tokens, - consumers, request_tokens), will result in a NotImplementedError, - and a message. - - >>> manager.access_tokens.blah - NotImplementedError: To use 'access_tokens' oauthlib must be installed - - Otherwise, if trying to access an attribute other than the ones in name, - the manager will state that the attribute does not exist. - - >>> manager.dne.blah - AttributeError: 'OAuthManagerOptionalImportProxy' object has no - attribute 'dne' - """ - - def __getattribute__(self, name): - """Return error when name is related to oauthlib and not exist.""" - if name in ('access_tokens', 'consumers', 'request_tokens'): - raise NotImplementedError( - _('To use %r oauthlib must be installed') % name) - return super(OAuthManagerOptionalImportProxy, - self).__getattribute__(name) diff --git a/keystoneclient/v3/contrib/oauth1/request_tokens.py b/keystoneclient/v3/contrib/oauth1/request_tokens.py deleted file mode 100644 index 59f06bcb..00000000 --- a/keystoneclient/v3/contrib/oauth1/request_tokens.py +++ /dev/null @@ -1,73 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import unicode_literals - -from keystoneauth1 import plugin -from six.moves.urllib import parse as urlparse - -from keystoneclient import base -from keystoneclient.v3.contrib.oauth1 import utils - -try: - from oauthlib import oauth1 -except ImportError: - oauth1 = None - - -class RequestToken(base.Resource): - def authorize(self, roles): - try: - retval = self.manager.authorize(self.id, roles) - self = retval - except Exception: - retval = None - - return retval - - -class RequestTokenManager(base.CrudManager): - """Manager class for manipulating identity OAuth request tokens.""" - - resource_class = RequestToken - - def authorize(self, request_token, roles): - """Authorize a request token with specific roles. - - Utilize Identity API operation: - PUT /OS-OAUTH1/authorize/$request_token_id - - :param request_token: a request token that will be authorized, and - can be exchanged for an access token. - :param roles: a list of roles, that will be delegated to the user. - """ - request_id = urlparse.quote(base.getid(request_token)) - endpoint = utils.OAUTH_PATH + '/authorize/%s' % (request_id) - body = {'roles': [{'id': base.getid(r_id)} for r_id in roles]} - return self._put(endpoint, body, "token") - - def create(self, consumer_key, consumer_secret, project): - endpoint = utils.OAUTH_PATH + '/request_token' - headers = {'requested-project-id': base.getid(project)} - oauth_client = oauth1.Client(consumer_key, - client_secret=consumer_secret, - signature_method=oauth1.SIGNATURE_HMAC, - callback_uri="oob") - url = self.client.get_endpoint(interface=plugin.AUTH_INTERFACE).rstrip( - "/") - url, headers, body = oauth_client.sign(url + endpoint, - http_method='POST', - headers=headers) - resp, body = self.client.post(endpoint, headers=headers) - token = utils.get_oauth_token_from_body(resp.content) - return self.resource_class(self, token) diff --git a/keystoneclient/v3/contrib/oauth1/utils.py b/keystoneclient/v3/contrib/oauth1/utils.py deleted file mode 100644 index 3c5c9d48..00000000 --- a/keystoneclient/v3/contrib/oauth1/utils.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import six -from six.moves.urllib import parse as urlparse - - -OAUTH_PATH = '/OS-OAUTH1' - - -def get_oauth_token_from_body(body): - """Parse the URL response body to retrieve the oauth token key and secret. - - The response body will look like: - 'oauth_token=12345&oauth_token_secret=67890' with - 'oauth_expires_at=2013-03-30T05:27:19.463201' possibly there, too. - """ - if six.PY3: - body = body.decode('utf-8') - - credentials = urlparse.parse_qs(body) - key = credentials['oauth_token'][0] - secret = credentials['oauth_token_secret'][0] - token = {'key': key, 'id': key, 'secret': secret} - expires_at = credentials.get('oauth_expires_at') - if expires_at: - token['expires'] = expires_at[0] - return token diff --git a/keystoneclient/v3/contrib/simple_cert.py b/keystoneclient/v3/contrib/simple_cert.py deleted file mode 100644 index 8168e67a..00000000 --- a/keystoneclient/v3/contrib/simple_cert.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2014 IBM Corp. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -class SimpleCertManager(object): - """Manager for the OS-SIMPLE-CERT extension.""" - - def __init__(self, client): - self._client = client - - def get_ca_certificates(self): - """Get CA certificates. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/OS-SIMPLE-CERT/ca', - authenticated=False) - return resp.text - - def get_certificates(self): - """Get signing certificates. - - :returns: PEM-formatted string. - :rtype: str - - """ - resp, body = self._client.get('/OS-SIMPLE-CERT/certificates', - authenticated=False) - return resp.text diff --git a/keystoneclient/v3/contrib/trusts.py b/keystoneclient/v3/contrib/trusts.py deleted file mode 100644 index a8ef5790..00000000 --- a/keystoneclient/v3/contrib/trusts.py +++ /dev/null @@ -1,102 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ -from keystoneclient import utils - - -class Trust(base.Resource): - """Represents a Trust. - - Attributes: - * id: a uuid that identifies the trust - * impersonation: allow explicit impersonation - * project_id: project ID - * trustee_user_id: a uuid that identifies the trustee - * trustor_user_id: a uuid that identifies the trustor - """ - - pass - - -class TrustManager(base.CrudManager): - """Manager class for manipulating Trusts.""" - - resource_class = Trust - collection_key = 'trusts' - key = 'trust' - base_url = '/OS-TRUST' - - def create(self, trustee_user, trustor_user, role_names=None, - role_ids=None, project=None, impersonation=False, - expires_at=None, remaining_uses=None, **kwargs): - """Create a Trust. - - :param string trustee_user: user who is capable of consuming the trust - :param string trustor_user: user who's authorization is being delegated - :param string role_names: subset of trustor's roles to be granted - :param string role_ids: subset of trustor's roles to be granted - :param string project: project which the trustor is delegating - :param boolean impersonation: enable explicit impersonation - :param datetime.datetime expires_at: expiry time - :param integer remaining_uses: how many times this trust can be used - to generate a token. None means - unlimited tokens. - - """ - # Convert role_names list into list-of-dict API format - roles = [] - if role_names: - roles.extend([{'name': n} for n in role_names]) - if role_ids: - roles.extend([{'id': i} for i in role_ids]) - - if not roles: - roles = None - - # Convert datetime.datetime expires_at to iso format string - if expires_at: - expires_str = utils.isotime(at=expires_at, subsecond=True) - else: - expires_str = None - - return super(TrustManager, self).create( - expires_at=expires_str, - impersonation=impersonation, - project_id=base.getid(project), - remaining_uses=remaining_uses, - roles=roles, - trustee_user_id=base.getid(trustee_user), - trustor_user_id=base.getid(trustor_user), - **kwargs) - - def update(self): - raise exceptions.MethodNotImplemented( - _('Update not supported for trusts')) - - def list(self, trustee_user=None, trustor_user=None, **kwargs): - """List Trusts.""" - trustee_user_id = base.getid(trustee_user) - trustor_user_id = base.getid(trustor_user) - return super(TrustManager, self).list(trustee_user_id=trustee_user_id, - trustor_user_id=trustor_user_id, - **kwargs) - - def get(self, trust): - """Get a specific trust.""" - return super(TrustManager, self).get(trust_id=base.getid(trust)) - - def delete(self, trust): - """Delete a trust.""" - return super(TrustManager, self).delete(trust_id=base.getid(trust)) diff --git a/keystoneclient/v3/credentials.py b/keystoneclient/v3/credentials.py deleted file mode 100644 index 80eb38b3..00000000 --- a/keystoneclient/v3/credentials.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Credential(base.Resource): - """Represents an Identity credential. - - Attributes: - * id: a uuid that identifies the credential - * user_id: user ID to which credential belongs - * type: the type of credential - * blob: the text that represents the credential - * project_id: project ID which limits the scope of the credential - - """ - - pass - - -class CredentialManager(base.CrudManager): - """Manager class for manipulating Identity credentials.""" - - resource_class = Credential - collection_key = 'credentials' - key = 'credential' - - @positional(1, enforcement=positional.WARN) - def create(self, user, type, blob, project=None, **kwargs): - """Create a credential. - - :param user: the user to which the credential belongs - :type user: str or :class:`keystoneclient.v3.users.User` - :param str type: the type of the credential, valid values are: - ``ec2``, ``cert`` or ``totp`` - :param str blob: the arbitrary blob of the credential data, to be - parsed according to the type - :param project: the project which limits the scope of the credential, - this attribbute is mandatory if the credential type is - ec2 - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server - - :returns: the created credential - :rtype: :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).create( - user_id=base.getid(user), - type=type, - blob=blob, - project_id=base.getid(project), - **kwargs) - - def get(self, credential): - """Retrieve a credential. - - :param credential: the credential to be retrieved from the server - :type credential: str or - :class:`keystoneclient.v3.credentials.Credential` - - :returns: the specified credential - :rtype: :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).get( - credential_id=base.getid(credential)) - - def list(self, **kwargs): - """List credentials. - - :param kwargs: If user_id or type is specified then credentials - will be filtered accordingly. - - :returns: a list of credentials - :rtype: list of :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).list(**kwargs) - - @positional(2, enforcement=positional.WARN) - def update(self, credential, user, type=None, blob=None, project=None, - **kwargs): - """Update a credential. - - :param credential: the credential to be updated on the server - :type credential: str or - :class:`keystoneclient.v3.credentials.Credential` - :param user: the new user to which the credential belongs - :type user: str or :class:`keystoneclient.v3.users.User` - :param str type: the new type of the credential, valid values are: - ``ec2``, ``cert`` or ``totp`` - :param str blob: the new blob of the credential data - and may be removed in the future release. - :param project: the new project which limits the scope of the - credential, this attribute is mandatory if the - credential type is ec2 - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server - - :returns: the updated credential - :rtype: :class:`keystoneclient.v3.credentials.Credential` - - """ - return super(CredentialManager, self).update( - credential_id=base.getid(credential), - user_id=base.getid(user), - type=type, - blob=blob, - project_id=base.getid(project), - **kwargs) - - def delete(self, credential): - """Delete a credential. - - :param credential: the credential to be deleted - :type credential: str or - :class:`keystoneclient.v3.credentials.Credential` - - :returns: response object with 204 status - :rtype: :class:`requests.models.Response` - - """ - return super(CredentialManager, self).delete( - credential_id=base.getid(credential)) diff --git a/keystoneclient/v3/domain_configs.py b/keystoneclient/v3/domain_configs.py deleted file mode 100644 index 4c011bce..00000000 --- a/keystoneclient/v3/domain_configs.py +++ /dev/null @@ -1,130 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class DomainConfig(base.Resource): - """An object representing a domain config association. - - This resource object does not necessarily contain fixed attributes, as new - attributes are added in the server, they are supported here directly. - The currently supported configs are `identity` and `ldap`. - - """ - - pass - - -class DomainConfigManager(base.Manager): - """Manager class for manipulating domain config associations.""" - - resource_class = DomainConfig - key = 'config' - - def build_url(self, domain): - return '/domains/%s/config' % base.getid(domain) - - def create(self, domain, config): - """Create a config for a domain. - - :param domain: the domain where the config is going to be applied. - :type domain: str or :py:class:`keystoneclient.v3.domains.Domain` - - :param dict config: a dictionary of domain configurations. - - Example of the ``config`` parameter:: - - { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org" - } - } - - :returns: the created domain config returned from server. - :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig` - - """ - base_url = self.build_url(domain) - body = {self.key: config} - return super(DomainConfigManager, self)._put( - base_url, body=body, response_key=self.key) - - def get(self, domain): - """Get a config for a domain. - - :param domain: the domain for which the config is defined. - :type domain: str or :py:class:`keystoneclient.v3.domains.Domain` - - :returns: the domain config returned from server. - :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig` - - """ - base_url = self.build_url(domain) - return super(DomainConfigManager, self)._get(base_url, self.key) - - def update(self, domain, config): - """Update a config for a domain. - - :param domain: the domain where the config is going to be updated. - :type domain: str or :py:class:`keystoneclient.v3.domains.Domain` - - :param dict config: a dictionary of domain configurations. - - Example of the ``config`` parameter:: - - { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org" - } - } - - :returns: the updated domain config returned from server. - :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig` - - """ - base_url = self.build_url(domain) - body = {self.key: config} - return super(DomainConfigManager, self)._patch( - base_url, body=body, response_key=self.key) - - def delete(self, domain): - """Delete a config for a domain. - - :param domain: the domain which the config will be deleted on - the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - base_url = self.build_url(domain) - return super(DomainConfigManager, self)._delete(url=base_url) - - def find(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Find not supported for domain configs')) - - def list(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('List not supported for domain configs')) diff --git a/keystoneclient/v3/domains.py b/keystoneclient/v3/domains.py deleted file mode 100644 index a790558f..00000000 --- a/keystoneclient/v3/domains.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Domain(base.Resource): - """Represents an Identity domain. - - Attributes: - * id: a uuid that identifies the domain - * name: the name of the domain - * description: a description of the domain - * enabled: determines whether the domain is enabled - - """ - - pass - - -class DomainManager(base.CrudManager): - """Manager class for manipulating Identity domains.""" - - resource_class = Domain - collection_key = 'domains' - key = 'domain' - - @positional(1, enforcement=positional.WARN) - def create(self, name, description=None, enabled=True, **kwargs): - """Create a domain. - - :param str name: the name of the domain. - :param str description: a description of the domain. - :param bool enabled: whether the domain is enabled. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created domain returned from server. - :rtype: :class:`keystoneclient.v3.domains.Domain` - - """ - return super(DomainManager, self).create( - name=name, - description=description, - enabled=enabled, - **kwargs) - - def get(self, domain): - """Retrieve a domain. - - :param domain: the domain to be retrieved from the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - - :returns: the specified domain returned from server. - :rtype: :class:`keystoneclient.v3.domains.Domain` - - """ - return super(DomainManager, self).get( - domain_id=base.getid(domain)) - - def list(self, **kwargs): - """List domains. - - :param kwargs: allows filter criteria to be passed where - supported by the server. - - :returns: a list of domains. - :rtype: list of :class:`keystoneclient.v3.domains.Domain`. - - """ - # Ref bug #1267530 we have to pass 0 for False to get the expected - # results on all keystone versions - if kwargs.get('enabled') is False: - kwargs['enabled'] = 0 - return super(DomainManager, self).list(**kwargs) - - @positional(enforcement=positional.WARN) - def update(self, domain, name=None, - description=None, enabled=None, **kwargs): - """Update a domain. - - :param domain: the domain to be updated on the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str name: the new name of the domain. - :param str description: the new description of the domain. - :param bool enabled: whether the domain is enabled. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated domain returned from server. - :rtype: :class:`keystoneclient.v3.domains.Domain` - - """ - return super(DomainManager, self).update( - domain_id=base.getid(domain), - name=name, - description=description, - enabled=enabled, - **kwargs) - - def delete(self, domain): - """"Delete a domain. - - :param domain: the domain to be deleted on the server. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(DomainManager, self).delete( - domain_id=base.getid(domain)) diff --git a/keystoneclient/v3/ec2.py b/keystoneclient/v3/ec2.py deleted file mode 100644 index d32fbcaa..00000000 --- a/keystoneclient/v3/ec2.py +++ /dev/null @@ -1,98 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class EC2(base.Resource): - """Represents an EC2 resource. - - Attributes: - * id: a string that identifies the EC2 resource. - * user_id: the ID field of a pre-existing user in the backend. - * project_id: the ID field of a pre-existing project in the backend. - * access: a string representing access key of the access/secret pair. - * secret: a string representing the secret of the access/secret pair. - - """ - - def __repr__(self): - """Return string representation of EC2 resource information.""" - return "" % self._info - - -class EC2Manager(base.ManagerWithFind): - - resource_class = EC2 - - def create(self, user_id, project_id): - """Create a new access/secret pair. - - :param user_id: the ID of the user having access/secret pair. - :type user_id: str or :class:`keystoneclient.v3.users.User` - :param project_id: the ID of the project having access/secret pair. - :type project_id: str or :class:`keystoneclient.v3.projects.Project` - - :returns: the created access/secret pair returned from server. - :rtype: :class:`keystoneclient.v3.ec2.EC2` - - """ - # NOTE(jamielennox): Yes, this uses tenant_id as a key even though we - # are in the v3 API. - return self._post('/users/%s/credentials/OS-EC2' % user_id, - body={'tenant_id': project_id}, - response_key="credential") - - def get(self, user_id, access): - """Retrieve an access/secret pair for a given access key. - - :param user_id: the ID of the user whose access/secret pair will be - retrieved from the server. - :type user_id: str or :class:`keystoneclient.v3.users.User` - :param str access: the access key whose access/secret pair will be - retrieved from the server. - - :returns: the specified access/secret pair returned from server. - :rtype: :class:`keystoneclient.v3.ec2.EC2` - - """ - url = "/users/%s/credentials/OS-EC2/%s" % (user_id, base.getid(access)) - return self._get(url, response_key="credential") - - def list(self, user_id): - """List access/secret pairs for a given user. - - :param str user_id: the ID of the user having access/secret pairs will - be listed. - - :returns: a list of access/secret pairs. - :rtype: list of :class:`keystoneclient.v3.ec2.EC2` - - """ - return self._list("/users/%s/credentials/OS-EC2" % user_id, - response_key="credentials") - - def delete(self, user_id, access): - """Delete an access/secret pair. - - :param user_id: the ID of the user whose access/secret pair will be - deleted on the server. - :type user_id: str or :class:`keystoneclient.v3.users.User` - :param str access: the access key whose access/secret pair will be - deleted on the server. - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return self._delete("/users/%s/credentials/OS-EC2/%s" % - (user_id, base.getid(access))) diff --git a/keystoneclient/v3/endpoint_groups.py b/keystoneclient/v3/endpoint_groups.py deleted file mode 100644 index f8b47c4d..00000000 --- a/keystoneclient/v3/endpoint_groups.py +++ /dev/null @@ -1,136 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class EndpointGroup(base.Resource): - """Represents an identity endpoint group. - - Attributes: - * id: a UUID that identifies the endpoint group - * name: the endpoint group name - * description: the endpoint group description - * filters: representation of filters in the format of JSON that define - what endpoint entities are part of the group - - """ - - pass - - -class EndpointGroupManager(base.CrudManager): - """Manager class for Endpoint Groups.""" - - resource_class = EndpointGroup - collection_key = 'endpoint_groups' - key = 'endpoint_group' - base_url = 'OS-EP-FILTER' - - def create(self, name, filters, description=None, **kwargs): - """Create an endpoint group. - - :param str name: the name of the endpoint group. - :param str filters: representation of filters in the format of JSON - that define what endpoint entities are part of the - group. - :param str description: a description of the endpoint group. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created endpoint group returned from server. - :rtype: :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - """ - return super(EndpointGroupManager, self).create( - name=name, - filters=filters, - description=description, - **kwargs) - - def get(self, endpoint_group): - """Retrieve an endpoint group. - - :param endpoint_group: the endpoint group to be retrieved from the - server. - :type endpoint_group: - str or :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - :returns: the specified endpoint group returned from server. - :rtype: :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - """ - return super(EndpointGroupManager, self).get( - endpoint_group_id=base.getid(endpoint_group)) - - def check(self, endpoint_group): - """Check if an endpoint group exists. - - :param endpoint_group: the endpoint group to be checked against the - server. - :type endpoint_group: - str or :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - :returns: none if the specified endpoint group exists. - - """ - return super(EndpointGroupManager, self).head( - endpoint_group_id=base.getid(endpoint_group)) - - def list(self, **kwargs): - """List endpoint groups. - - Any parameter provided will be passed to the server. - - :returns: a list of endpoint groups. - :rtype: list of - :class:`keystoneclient.v3.endpoint_groups.EndpointGroup`. - - """ - return super(EndpointGroupManager, self).list(**kwargs) - - def update(self, endpoint_group, name=None, filters=None, - description=None, **kwargs): - """Update an endpoint group. - - :param str name: the new name of the endpoint group. - :param str filters: the new representation of filters in the format of - JSON that define what endpoint entities are part of - the group. - :param str description: the new description of the endpoint group. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated endpoint group returned from server. - :rtype: :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - """ - return super(EndpointGroupManager, self).update( - endpoint_group_id=base.getid(endpoint_group), - name=name, - filters=filters, - description=description, - **kwargs) - - def delete(self, endpoint_group): - """Delete an endpoint group. - - :param endpoint_group: the endpoint group to be deleted on the server. - :type endpoint_group: - str or :class:`keystoneclient.v3.endpoint_groups.EndpointGroup` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(EndpointGroupManager, self).delete( - endpoint_group_id=base.getid(endpoint_group)) diff --git a/keystoneclient/v3/endpoints.py b/keystoneclient/v3/endpoints.py deleted file mode 100644 index bc8ccb61..00000000 --- a/keystoneclient/v3/endpoints.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -VALID_INTERFACES = ['public', 'admin', 'internal'] - - -class Endpoint(base.Resource): - """Represents an Identity endpoint. - - Attributes: - * id: a uuid that identifies the endpoint - * interface: 'public', 'admin' or 'internal' network interface - * region: geographic location of the endpoint - * service_id: service to which the endpoint belongs - * url: fully qualified service endpoint - * enabled: determines whether the endpoint appears in the service - catalog - - """ - - pass - - -class EndpointManager(base.CrudManager): - """Manager class for manipulating Identity endpoints.""" - - resource_class = Endpoint - collection_key = 'endpoints' - key = 'endpoint' - - def _validate_interface(self, interface): - if interface is not None and interface not in VALID_INTERFACES: - msg = _('"interface" must be one of: %s') - msg %= ', '.join(VALID_INTERFACES) - raise exceptions.ValidationError(msg) - - @positional(1, enforcement=positional.WARN) - def create(self, service, url, interface=None, region=None, enabled=True, - **kwargs): - """Create an endpoint. - - :param service: the service to which the endpoint belongs. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str url: the URL of the fully qualified service endpoint. - :param str interface: the network interface of the endpoint. Valid - values are: ``public``, ``admin`` or ``internal``. - :param region: the region to which the endpoint belongs. - :type region: str or :class:`keystoneclient.v3.regions.Region` - :param bool enabled: whether the endpoint is enabled or not, - determining if it appears in the service catalog. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created endpoint returned from server. - :rtype: :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - self._validate_interface(interface) - return super(EndpointManager, self).create( - service_id=base.getid(service), - interface=interface, - url=url, - region=region, - enabled=enabled, - **kwargs) - - def get(self, endpoint): - """Retrieve an endpoint. - - :param endpoint: the endpoint to be retrieved from the server. - :type endpoint: str or :class:`keystoneclient.v3.endpoints.Endpoint` - - :returns: the specified endpoint returned from server. - :rtype: :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - return super(EndpointManager, self).get( - endpoint_id=base.getid(endpoint)) - - @positional(enforcement=positional.WARN) - def list(self, service=None, interface=None, region=None, enabled=None, - region_id=None, **kwargs): - """List endpoints. - - :param service: the service of the endpoints to be filtered on. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str interface: the network interface of the endpoints to be - filtered on. Valid values are: ``public``, - ``admin`` or ``internal``. - :param bool enabled: whether to return enabled or disabled endpoints. - :param str region_id: filter endpoints by the region_id attribute. If - both region and region_id are specified, region - takes precedence. - :param kwargs: any other attribute provided will filter endpoints on. - - :returns: a list of endpoints. - :rtype: list of :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - # NOTE(lhcheng): region filter is not supported by keystone, - # region_id should be used instead. Consider removing the - # region argument in the next release. - self._validate_interface(interface) - return super(EndpointManager, self).list( - service_id=base.getid(service), - interface=interface, - region_id=region_id or base.getid(region), - enabled=enabled, - **kwargs) - - @positional(enforcement=positional.WARN) - def update(self, endpoint, service=None, url=None, interface=None, - region=None, enabled=None, **kwargs): - """Update an endpoint. - - :param endpoint: the endpoint to be updated on the server. - :type endpoint: str or :class:`keystoneclient.v3.endpoints.Endpoint` - :param service: the new service to which the endpoint belongs. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str url: the new URL of the fully qualified service endpoint. - :param str interface: the new network interface of the endpoint. Valid - values are: ``public``, ``admin`` or ``internal``. - :param region: the new region to which the endpoint belongs. - :type region: str or :class:`keystoneclient.v3.regions.Region` - :param bool enabled: determining if the endpoint appears in the service - catalog by enabling or disabling it. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated endpoint returned from server. - :rtype: :class:`keystoneclient.v3.endpoints.Endpoint` - - """ - self._validate_interface(interface) - return super(EndpointManager, self).update( - endpoint_id=base.getid(endpoint), - service_id=base.getid(service), - interface=interface, - url=url, - region=region, - enabled=enabled, - **kwargs) - - def delete(self, endpoint): - """Delete an endpoint. - - :param endpoint: the endpoint to be deleted on the server. - :type endpoint: str or :class:`keystoneclient.v3.endpoints.Endpoint` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(EndpointManager, self).delete( - endpoint_id=base.getid(endpoint)) diff --git a/keystoneclient/v3/groups.py b/keystoneclient/v3/groups.py deleted file mode 100644 index 2eec3244..00000000 --- a/keystoneclient/v3/groups.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Group(base.Resource): - """Represents an Identity user group. - - Attributes: - * id: a uuid that identifies the group - * name: group name - * description: group description - - """ - - @positional(enforcement=positional.WARN) - def update(self, name=None, description=None): - kwargs = { - 'name': name if name is not None else self.name, - 'description': (description - if description is not None - else self.description), - } - - try: - retval = self.manager.update(self.id, **kwargs) - self = retval - except Exception: - retval = None - - return retval - - -class GroupManager(base.CrudManager): - """Manager class for manipulating Identity groups.""" - - resource_class = Group - collection_key = 'groups' - key = 'group' - - @positional(1, enforcement=positional.WARN) - def create(self, name, domain=None, description=None, **kwargs): - """Create a group. - - :param str name: the name of the group. - :param domain: the domain of the group. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str description: a description of the group. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created group returned from server. - :rtype: :class:`keystoneclient.v3.groups.Group` - - """ - return super(GroupManager, self).create( - name=name, - domain_id=base.getid(domain), - description=description, - **kwargs) - - @positional(enforcement=positional.WARN) - def list(self, user=None, domain=None, **kwargs): - """List groups. - - :param user: the user of the groups to be filtered on. - :type user: str or :class:`keystoneclient.v3.users.User` - :param domain: the domain of the groups to be filtered on. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param kwargs: any other attribute provided will filter groups on. - - :returns: a list of groups. - :rtype: list of :class:`keystoneclient.v3.groups.Group`. - - """ - if user: - base_url = '/users/%s' % base.getid(user) - else: - base_url = None - return super(GroupManager, self).list( - base_url=base_url, - domain_id=base.getid(domain), - **kwargs) - - def get(self, group): - """Retrieve a group. - - :param group: the group to be retrieved from the server. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: the specified group returned from server. - :rtype: :class:`keystoneclient.v3.groups.Group` - - """ - return super(GroupManager, self).get( - group_id=base.getid(group)) - - @positional(enforcement=positional.WARN) - def update(self, group, name=None, description=None, **kwargs): - """Update a group. - - :param group: the group to be updated on the server. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param str name: the new name of the group. - :param str description: the new description of the group. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated group returned from server. - :rtype: :class:`keystoneclient.v3.groups.Group` - - """ - return super(GroupManager, self).update( - group_id=base.getid(group), - name=name, - description=description, - **kwargs) - - def delete(self, group): - """Delete a group. - - :param group: the group to be deleted on the server. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(GroupManager, self).delete( - group_id=base.getid(group)) diff --git a/keystoneclient/v3/policies.py b/keystoneclient/v3/policies.py deleted file mode 100644 index a9be680d..00000000 --- a/keystoneclient/v3/policies.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Policy(base.Resource): - """Represents an Identity policy. - - Attributes: - * id: a uuid that identifies the policy - * blob: a policy document (blob) - * type: the MIME type of the policy blob - - """ - - @positional(enforcement=positional.WARN) - def update(self, blob=None, type=None): - kwargs = { - 'blob': blob if blob is not None else self.blob, - 'type': type if type is not None else self.type, - } - - try: - retval = self.manager.update(self.id, **kwargs) - self = retval - except Exception: - retval = None - - return retval - - -class PolicyManager(base.CrudManager): - """Manager class for manipulating Identity policies.""" - - resource_class = Policy - collection_key = 'policies' - key = 'policy' - - @positional(1, enforcement=positional.WARN) - def create(self, blob, type='application/json', **kwargs): - """Create a policy. - - :param str blob: the policy document. - :param str type: the MIME type of the policy blob. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created policy returned from server. - :rtype: :class:`keystoneclient.v3.policies.Policy` - - """ - return super(PolicyManager, self).create( - blob=blob, - type=type, - **kwargs) - - def get(self, policy): - """Retrieve a policy. - - :param policy: the policy to be retrieved from the server. - :type policy: str or :class:`keystoneclient.v3.policies.Policy` - - :returns: the specified policy returned from server. - :rtype: :class:`keystoneclient.v3.policies.Policy` - - """ - return super(PolicyManager, self).get( - policy_id=base.getid(policy)) - - def list(self, **kwargs): - """List policies. - - :param kwargs: allows filter criteria to be passed where - supported by the server. - - :returns: a list of policies. - :rtype: list of :class:`keystoneclient.v3.policies.Policy`. - - """ - return super(PolicyManager, self).list(**kwargs) - - @positional(enforcement=positional.WARN) - def update(self, policy, blob=None, type=None, **kwargs): - """Update a policy. - - :param policy: the policy to be updated on the server. - :type policy: str or :class:`keystoneclient.v3.policies.Policy` - :param str blob: the new policy document. - :param str type: the new MIME type of the policy blob. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the updated policy returned from server. - :rtype: :class:`keystoneclient.v3.policies.Policy` - - """ - return super(PolicyManager, self).update( - policy_id=base.getid(policy), - blob=blob, - type=type, - **kwargs) - - def delete(self, policy): - """"Delete a policy. - - :param policy: the policy to be deleted on the server. - :type policy: str or :class:`keystoneclient.v3.policies.Policy` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(PolicyManager, self).delete( - policy_id=base.getid(policy)) diff --git a/keystoneclient/v3/projects.py b/keystoneclient/v3/projects.py deleted file mode 100644 index 81dcf8d9..00000000 --- a/keystoneclient/v3/projects.py +++ /dev/null @@ -1,222 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class Project(base.Resource): - """Represents an Identity project. - - Attributes: - * id: a uuid that identifies the project - * name: project name - * description: project description - * enabled: boolean to indicate if project is enabled - * parent_id: a uuid representing this project's parent in hierarchy - * parents: a list or a structured dict containing the parents of this - project in the hierarchy - * subtree: a list or a structured dict containing the subtree of this - project in the hierarchy - - """ - - @positional(enforcement=positional.WARN) - def update(self, name=None, description=None, enabled=None): - kwargs = { - 'name': name if name is not None else self.name, - 'description': (description - if description is not None - else self.description), - 'enabled': enabled if enabled is not None else self.enabled, - } - - try: - retval = self.manager.update(self.id, **kwargs) - self = retval - except Exception: - retval = None - - return retval - - -class ProjectManager(base.CrudManager): - """Manager class for manipulating Identity projects.""" - - resource_class = Project - collection_key = 'projects' - key = 'project' - - @positional(3, enforcement=positional.WARN) - def create(self, name, domain, description=None, - enabled=True, parent=None, **kwargs): - """Create a project. - - :param str name: the name of the project. - :param domain: the domain of the project. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str description: the description of the project. - :param bool enabled: whether the project is enabled. - :param parent: the parent of the project in the hierarchy. - :type parent: str or :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created project returned from server. - :rtype: :class:`keystoneclient.v3.projects.Project` - - """ - # NOTE(rodrigods): the API must be backwards compatible, so if an - # application was passing a 'parent_id' before as kwargs, the call - # should not fail. If both 'parent' and 'parent_id' are provided, - # 'parent' will be preferred. - if parent: - kwargs['parent_id'] = base.getid(parent) - - return super(ProjectManager, self).create( - domain_id=base.getid(domain), - name=name, - description=description, - enabled=enabled, - **kwargs) - - @positional(enforcement=positional.WARN) - def list(self, domain=None, user=None, **kwargs): - """List projects. - - :param domain: the domain of the projects to be filtered on. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param user: filter in projects the specified user has role - assignments on. - :type user: str or :class:`keystoneclient.v3.users.User` - :param kwargs: any other attribute provided will filter projects on. - - :returns: a list of projects. - :rtype: list of :class:`keystoneclient.v3.projects.Project` - - """ - base_url = '/users/%s' % base.getid(user) if user else None - return super(ProjectManager, self).list( - base_url=base_url, - domain_id=base.getid(domain), - fallback_to_auth=True, - **kwargs) - - def _check_not_parents_as_ids_and_parents_as_list(self, parents_as_ids, - parents_as_list): - if parents_as_ids and parents_as_list: - msg = _('Specify either parents_as_ids or parents_as_list ' - 'parameters, not both') - raise exceptions.ValidationError(msg) - - def _check_not_subtree_as_ids_and_subtree_as_list(self, subtree_as_ids, - subtree_as_list): - if subtree_as_ids and subtree_as_list: - msg = _('Specify either subtree_as_ids or subtree_as_list ' - 'parameters, not both') - raise exceptions.ValidationError(msg) - - @positional() - def get(self, project, subtree_as_list=False, parents_as_list=False, - subtree_as_ids=False, parents_as_ids=False): - """Retrieve a project. - - :param project: the project to be retrieved from the server. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool subtree_as_list: retrieve projects below this project in - the hierarchy as a flat list. It only - includes the projects in which the current - user has role assignments on. - :param bool parents_as_list: retrieve projects above this project in - the hierarchy as a flat list. It only - includes the projects in which the current - user has role assignments on. - :param bool subtree_as_ids: retrieve the IDs from the projects below - this project in the hierarchy as a - structured dictionary. - :param bool parents_as_ids: retrieve the IDs from the projects above - this project in the hierarchy as a - structured dictionary. - :returns: the specified project returned from server. - :rtype: :class:`keystoneclient.v3.projects.Project` - - :raises keystoneclient.exceptions.ValidationError: if subtree_as_list - and subtree_as_ids or parents_as_list and parents_as_ids are - included at the same time in the call. - - """ - self._check_not_parents_as_ids_and_parents_as_list( - parents_as_ids, parents_as_list) - self._check_not_subtree_as_ids_and_subtree_as_list( - subtree_as_ids, subtree_as_list) - - # According to the API spec, the query params are key only - query_params = [] - if subtree_as_list: - query_params.append('subtree_as_list') - if subtree_as_ids: - query_params.append('subtree_as_ids') - if parents_as_list: - query_params.append('parents_as_list') - if parents_as_ids: - query_params.append('parents_as_ids') - - query = self.build_key_only_query(query_params) - dict_args = {'project_id': base.getid(project)} - url = self.build_url(dict_args_in_out=dict_args) - return self._get(url + query, self.key) - - @positional(enforcement=positional.WARN) - def update(self, project, name=None, domain=None, description=None, - enabled=None, **kwargs): - """Update a project. - - :param project: the project to be updated on the server. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param str name: the new name of the project. - :param domain: the new domain of the project. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param str description: the new description of the project. - :param bool enabled: whether the project is enabled. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated project returned from server. - :rtype: :class:`keystoneclient.v3.projects.Project` - - """ - return super(ProjectManager, self).update( - project_id=base.getid(project), - domain_id=base.getid(domain), - name=name, - description=description, - enabled=enabled, - **kwargs) - - def delete(self, project): - """Delete a project. - - :param project: the project to be deleted on the server. - :type project: str or :class:`keystoneclient.v3.projects.Project` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(ProjectManager, self).delete( - project_id=base.getid(project)) diff --git a/keystoneclient/v3/regions.py b/keystoneclient/v3/regions.py deleted file mode 100644 index 7783b3fc..00000000 --- a/keystoneclient/v3/regions.py +++ /dev/null @@ -1,119 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base - - -class Region(base.Resource): - """Represents a Catalog region. - - Attributes: - * id: a string that identifies the region. - * description: a string that describes the region. - * parent_region_id: a pre-existing region in the backend or its ID - field. Allows for hierarchical region organization. - * enabled: determines whether the endpoint appears in the catalog. - """ - - pass - - -class RegionManager(base.CrudManager): - """Manager class for manipulating Identity regions.""" - - resource_class = Region - collection_key = 'regions' - key = 'region' - - def create(self, id=None, description=None, enabled=True, - parent_region=None, **kwargs): - """Create a region. - - :param str id: the unique identifier of the region. If not specified an - ID will be created by the server. - :param str description: the description of the region. - :param bool enabled: whether the region is enabled or not, determining - if it appears in the catalog. - :param parent_region: the parent of the region in the hierarchy. - :type parent_region: str or :class:`keystoneclient.v3.regions.Region` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created region returned from server. - :rtype: :class:`keystoneclient.v3.regions.Region` - - """ - return super(RegionManager, self).create( - id=id, description=description, enabled=enabled, - parent_region_id=base.getid(parent_region), **kwargs) - - def get(self, region): - """Retrieve a region. - - :param region: the region to be retrieved from the server. - :type region: str or :class:`keystoneclient.v3.regions.Region` - - :returns: the specified region returned from server. - :rtype: :class:`keystoneclient.v3.regions.Region` - - """ - return super(RegionManager, self).get( - region_id=base.getid(region)) - - def list(self, **kwargs): - """List regions. - - :param kwargs: any attributes provided will filter regions on. - - :returns: a list of regions. - :rtype: list of :class:`keystoneclient.v3.regions.Region`. - - """ - return super(RegionManager, self).list( - **kwargs) - - def update(self, region, description=None, enabled=None, - parent_region=None, **kwargs): - """Update a region. - - :param region: the region to be updated on the server. - :type region: str or :class:`keystoneclient.v3.regions.Region` - :param str description: the new description of the region. - :param bool enabled: determining if the region appears in the catalog - by enabling or disabling it. - :param parent_region: the new parent of the region in the hierarchy. - :type parent_region: str or :class:`keystoneclient.v3.regions.Region` - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated region returned from server. - :rtype: :class:`keystoneclient.v3.regions.Region` - - """ - return super(RegionManager, self).update( - region_id=base.getid(region), - description=description, - enabled=enabled, - parent_region_id=base.getid(parent_region), - **kwargs) - - def delete(self, region): - """Delete a region. - - :param region: the region to be deleted on the server. - :type region: str or :class:`keystoneclient.v3.regions.Region` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(RegionManager, self).delete( - region_id=base.getid(region)) diff --git a/keystoneclient/v3/role_assignments.py b/keystoneclient/v3/role_assignments.py deleted file mode 100644 index 5360a948..00000000 --- a/keystoneclient/v3/role_assignments.py +++ /dev/null @@ -1,125 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class RoleAssignment(base.Resource): - """Represents an Identity role assignment. - - Attributes: - * role: an object which contains a role uuid - * user or group: an object which contains either a user or - group uuid - * scope: an object which has either a project or domain object - containing an uuid - """ - - pass - - -class RoleAssignmentManager(base.CrudManager): - """Manager class for manipulating Identity roles assignments.""" - - resource_class = RoleAssignment - collection_key = 'role_assignments' - key = 'role_assignment' - - def _check_not_user_and_group(self, user, group): - if user and group: - msg = _('Specify either a user or group, not both') - raise exceptions.ValidationError(msg) - - def _check_not_domain_and_project(self, domain, project): - if domain and project: - msg = _('Specify either a domain or project, not both') - raise exceptions.ValidationError(msg) - - def list(self, user=None, group=None, project=None, domain=None, role=None, - effective=False, os_inherit_extension_inherited_to=None, - include_subtree=False, include_names=False): - """List role assignments. - - If no arguments are provided, all role assignments in the - system will be listed. - - If both user and group are provided, a ValidationError will be - raised. If both domain and project are provided, it will also - raise a ValidationError. - - :param user: User to be used as query filter. (optional) - :param group: Group to be used as query filter. (optional) - :param project: Project to be used as query filter. - (optional) - :param domain: Domain to be used as query - filter. (optional) - :param role: Role to be used as query filter. (optional) - :param boolean effective: return effective role - assignments. (optional) - :param string os_inherit_extension_inherited_to: - return inherited role assignments for either 'projects' or - 'domains'. (optional) - :param boolean include_subtree: Include subtree (optional) - :param boolean include_names: Display names instead - of IDs. (optional) - """ - self._check_not_user_and_group(user, group) - self._check_not_domain_and_project(domain, project) - - query_params = {} - if user: - query_params['user.id'] = base.getid(user) - if group: - query_params['group.id'] = base.getid(group) - if project: - query_params['scope.project.id'] = base.getid(project) - if domain: - query_params['scope.domain.id'] = base.getid(domain) - if role: - query_params['role.id'] = base.getid(role) - if effective: - query_params['effective'] = effective - if include_names: - query_params['include_names'] = include_names - if os_inherit_extension_inherited_to: - query_params['scope.OS-INHERIT:inherited_to'] = ( - os_inherit_extension_inherited_to) - if include_subtree: - query_params['include_subtree'] = include_subtree - - return super(RoleAssignmentManager, self).list(**query_params) - - def create(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Create not supported for role assignments')) - - def update(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Update not supported for role assignments')) - - def get(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Get not supported for role assignments')) - - def find(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Find not supported for role assignments')) - - def put(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Put not supported for role assignments')) - - def delete(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Delete not supported for role assignments')) diff --git a/keystoneclient/v3/roles.py b/keystoneclient/v3/roles.py deleted file mode 100644 index d5439ffe..00000000 --- a/keystoneclient/v3/roles.py +++ /dev/null @@ -1,536 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from debtcollector import removals -from positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class Role(base.Resource): - """Represents an Identity role. - - Attributes: - * id: a uuid that identifies the role - * name: user-facing identifier - * domain: optional domain for the role - - """ - - pass - - -class InferenceRule(base.Resource): - """Represents a rule that states one role implies another. - - Attributes: - * prior_role: this role implies the other - * implied_role: this role is implied by the other - - """ - - pass - - -class RoleManager(base.CrudManager): - """Manager class for manipulating Identity roles.""" - - resource_class = Role - collection_key = 'roles' - key = 'role' - deprecation_msg = 'keystoneclient.v3.roles.InferenceRuleManager' - - def _role_grants_base_url(self, user, group, domain, project, - use_inherit_extension): - # When called, we have already checked that only one of user & group - # and one of domain & project have been specified - params = {} - - if project: - params['project_id'] = base.getid(project) - base_url = '/projects/%(project_id)s' - elif domain: - params['domain_id'] = base.getid(domain) - base_url = '/domains/%(domain_id)s' - - if use_inherit_extension: - base_url = '/OS-INHERIT' + base_url - - if user: - params['user_id'] = base.getid(user) - base_url += '/users/%(user_id)s' - elif group: - params['group_id'] = base.getid(group) - base_url += '/groups/%(group_id)s' - - return base_url % params - - def _require_domain_xor_project(self, domain, project): - if domain and project: - msg = _('Specify either a domain or project, not both') - raise exceptions.ValidationError(msg) - elif not (domain or project): - msg = _('Must specify either a domain or project') - raise exceptions.ValidationError(msg) - - def _require_user_xor_group(self, user, group): - if user and group: - msg = _('Specify either a user or group, not both') - raise exceptions.ValidationError(msg) - elif not (user or group): - msg = _('Must specify either a user or group') - raise exceptions.ValidationError(msg) - - @positional(1, enforcement=positional.WARN) - def create(self, name, domain=None, **kwargs): - """Create a role. - - :param str name: the name of the role. - :param domain: the domain of the role. If a value is passed it is a - domain-scoped role, otherwise it's a global role. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - domain_id = None - if domain: - domain_id = base.getid(domain) - - return super(RoleManager, self).create( - name=name, - domain_id=domain_id, - **kwargs) - - def get(self, role): - """Retrieve a role. - - :param role: the role to be retrieved from the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: the specified role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - return super(RoleManager, self).get(role_id=base.getid(role)) - - @positional(enforcement=positional.WARN) - def list(self, user=None, group=None, domain=None, - project=None, os_inherit_extension_inherited=False, **kwargs): - """List roles and role grants. - - :param user: filter in role grants for the specified user on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: filter in role grants for the specified group on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: filter in role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: filter in role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will filter roles on. - - :returns: a list of roles. - :rtype: list of :class:`keystoneclient.v3.roles.Role` - - """ - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - if user or group: - self._require_user_xor_group(user, group) - self._require_domain_xor_project(domain, project) - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).list(base_url=base_url, - **kwargs) - - return super(RoleManager, self).list(**kwargs) - - @positional(enforcement=positional.WARN) - def update(self, role, name=None, **kwargs): - """Update a role. - - :param role: the role to be updated on the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param str name: the new name of the role. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - return super(RoleManager, self).update( - role_id=base.getid(role), - name=name, - **kwargs) - - def delete(self, role): - """Delete a role. - - When a role is deleted all the role inferences that have deleted role - as prior role will be deleted as well. - - :param role: the role to be deleted on the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(RoleManager, self).delete( - role_id=base.getid(role)) - - @positional(enforcement=positional.WARN) - def grant(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): - """Grant a role to a user or group on a domain or project. - - :param role: the role to be granted on the server. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param user: the specified user to have the role granted on a resource. - Domain or project must be specified. User and group are - mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the specified group to have the role granted on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: the domain in which the role will be granted. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: the project in which the role will be granted. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the granted role returned from server. - :rtype: :class:`keystoneclient.v3.roles.Role` - - """ - self._require_domain_xor_project(domain, project) - self._require_user_xor_group(user, group) - - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).put(base_url=base_url, - role_id=base.getid(role), - **kwargs) - - @positional(enforcement=positional.WARN) - def check(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): - """Check if a user or group has a role on a domain or project. - - :param user: check for role grants for the specified user on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: check for role grants for the specified group on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: check for role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: check for role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the specified role returned from server if it exists. - :rtype: :class:`keystoneclient.v3.roles.Role` - - :returns: Response object with 204 status if specified role - doesn't exist. - :rtype: :class:`requests.models.Response` - - """ - self._require_domain_xor_project(domain, project) - self._require_user_xor_group(user, group) - - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).head( - base_url=base_url, - role_id=base.getid(role), - os_inherit_extension_inherited=os_inherit_extension_inherited, - **kwargs) - - @positional(enforcement=positional.WARN) - def revoke(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): - """Revoke a role from a user or group on a domain or project. - - :param user: revoke role grants for the specified user on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: revoke role grants for the specified group on a - resource. Domain or project must be specified. - User and group are mutually exclusive. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param domain: revoke role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: revoke role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param bool os_inherit_extension_inherited: OS-INHERIT will be used. - It provides the ability for - projects to inherit role - assignments from their - domains or from parent - projects in the hierarchy. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the revoked role returned from server. - :rtype: list of :class:`keystoneclient.v3.roles.Role` - - """ - self._require_domain_xor_project(domain, project) - self._require_user_xor_group(user, group) - - if os_inherit_extension_inherited: - kwargs['tail'] = '/inherited_to_projects' - - base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) - return super(RoleManager, self).delete( - base_url=base_url, - role_id=base.getid(role), - os_inherit_extension_inherited=os_inherit_extension_inherited, - **kwargs) - - @removals.remove(message='Use %s.create instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def create_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).create(prior_role, - implied_role) - - @removals.remove(message='Use %s.delete instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def delete_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).delete(prior_role, - implied_role) - - @removals.remove(message='Use %s.get instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def get_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).get(prior_role, - implied_role) - - @removals.remove(message='Use %s.check instead.' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def check_implied(self, prior_role, implied_role, **kwargs): - return InferenceRuleManager(self.client).check(prior_role, - implied_role) - - @removals.remove(message='Use %s.list_inference_roles' % deprecation_msg, - version='3.9.0', removal_version='4.0.0') - def list_role_inferences(self, **kwargs): - return InferenceRuleManager(self.client).list_inference_roles() - - -class InferenceRuleManager(base.CrudManager): - """Manager class for manipulating Identity inference rules.""" - - resource_class = InferenceRule - collection_key = 'role_inferences' - key = 'role_inference' - - def _implied_role_url_tail(self, prior_role, implied_role): - base_url = ('/%(prior_role_id)s/implies/%(implied_role_id)s' % - {'prior_role_id': base.getid(prior_role), - 'implied_role_id': base.getid(implied_role)}) - return base_url - - def create(self, prior_role, implied_role): - """Create an inference rule. - - An inference rule is comprised of two roles, a prior role and an - implied role. The prior role will imply the implied role. - - Valid HTTP return codes: - - * 201: Resource is created successfully - * 404: A role cannot be found - * 409: The inference rule already exists - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: a newly created role inference returned from server. - :rtype: :class:`keystoneclient.v3.roles.InferenceRule` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - _resp, body = self.client.put("/roles" + url_tail) - return self.resource_class(self, body['role_inference']) - - def delete(self, prior_role, implied_role): - """Delete an inference rule. - - When deleting an inference rule, both roles are required. Note that - neither role is deleted, only the inference relationship is dissolved. - - Valid HTTP return codes: - - * 204: Delete request is accepted - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - return self.client.delete("/roles" + url_tail) - - def get(self, prior_role, implied_role): - """Retrieve an inference rule. - - Valid HTTP return codes: - - * 200: Inference rule is returned - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: the specified role inference returned from server. - :rtype: :class:`keystoneclient.v3.roles.InferenceRule` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - _resp, body = self.client.get("/roles" + url_tail) - return self.resource_class(self, body['role_inference']) - - def list(self, prior_role): - """List all roles that a role may imply. - - Valid HTTP return codes: - - * 200: List of inference rules are returned - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: the specified role inference returned from server. - :rtype: :class:`keystoneclient.v3.roles.InferenceRule` - - """ - url_tail = ('/%s/implies' % base.getid(prior_role)) - _resp, body = self.client.get("/roles" + url_tail) - return self.resource_class(self, body['role_inference']) - - def check(self, prior_role, implied_role): - """Check if an inference rule exists. - - Valid HTTP return codes: - - * 204: The rule inference exists - * 404: A role cannot be found - - :param prior_role: the role which implies ``implied_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - :param implied_role: the role which is implied by ``prior_role``. - :type role: str or :class:`keystoneclient.v3.roles.Role` - - :returns: response object with 204 status returned from server. - :rtype: :class:`requests.models.Response` - - """ - url_tail = self._implied_role_url_tail(prior_role, implied_role) - return self.client.head("/roles" + url_tail) - - def list_inference_roles(self): - """List all rule inferences. - - Valid HTTP return codes: - - * 200: All inference rules are returned - - :param kwargs: attributes provided will be passed to the server. - - :returns: a list of inference rules. - :rtype: list of :class:`keystoneclient.v3.roles.InferenceRule` - - """ - return super(InferenceRuleManager, self).list() - - def update(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Update not supported for rule inferences')) - - def find(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Find not supported for rule inferences')) - - def put(self, **kwargs): - raise exceptions.MethodNotImplemented( - _('Put not supported for rule inferences')) diff --git a/keystoneclient/v3/services.py b/keystoneclient/v3/services.py deleted file mode 100644 index d38e2d40..00000000 --- a/keystoneclient/v3/services.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import base - - -class Service(base.Resource): - """Represents an Identity service. - - Attributes: - * id: a uuid that identifies the service - * name: the user-facing name of the service (e.g. Keystone) - * description: a description of the service - * type: the type of the service (e.g. 'compute', 'identity') - * enabled: determines whether the service appears in the catalog - - """ - - pass - - -class ServiceManager(base.CrudManager): - """Manager class for manipulating Identity services.""" - - resource_class = Service - collection_key = 'services' - key = 'service' - - @positional(1, enforcement=positional.WARN) - def create(self, name, type=None, - enabled=True, description=None, **kwargs): - """Create a service. - - :param str name: the name of the service. - :param str type: the type of the service. - :param bool enabled: whether the service appears in the catalog. - :param str description: the description of the service. - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created service returned from server. - :rtype: :class:`keystoneclient.v3.services.Service` - - """ - type_arg = type or kwargs.pop('service_type', None) - return super(ServiceManager, self).create( - name=name, - type=type_arg, - description=description, - enabled=enabled, - **kwargs) - - def get(self, service): - """Retrieve a service. - - :param service: the service to be retrieved from the server. - :type service: str or :class:`keystoneclient.v3.services.Service` - - :returns: the specified service returned from server. - :rtype: :class:`keystoneclient.v3.services.Service` - - """ - return super(ServiceManager, self).get( - service_id=base.getid(service)) - - @positional(enforcement=positional.WARN) - def list(self, name=None, type=None, **kwargs): - """List services. - - :param str name: the name of the services to be filtered on. - :param str type: the type of the services to be filtered on. - :param kwargs: any other attribute provided will filter services on. - - :returns: a list of services. - :rtype: list of :class:`keystoneclient.v3.services.Service` - - """ - type_arg = type or kwargs.pop('service_type', None) - return super(ServiceManager, self).list( - name=name, - type=type_arg, - **kwargs) - - @positional(enforcement=positional.WARN) - def update(self, service, name=None, type=None, enabled=None, - description=None, **kwargs): - """Update a service. - - :param service: the service to be updated on the server. - :type service: str or :class:`keystoneclient.v3.services.Service` - :param str name: the new name of the service. - :param str type: the new type of the service. - :param bool enabled: whether the service appears in the catalog. - :param str description: the new description of the service. - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated service returned from server. - :rtype: :class:`keystoneclient.v3.services.Service` - - """ - type_arg = type or kwargs.pop('service_type', None) - return super(ServiceManager, self).update( - service_id=base.getid(service), - name=name, - type=type_arg, - description=description, - enabled=enabled, - **kwargs) - - def delete(self, service=None, id=None): - """Delete a service. - - :param service: the service to be deleted on the server. - :type service: str or :class:`keystoneclient.v3.services.Service` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - if service: - service_id = base.getid(service) - else: - service_id = id - return super(ServiceManager, self).delete( - service_id=service_id) diff --git a/keystoneclient/v3/tokens.py b/keystoneclient/v3/tokens.py deleted file mode 100644 index 77f60458..00000000 --- a/keystoneclient/v3/tokens.py +++ /dev/null @@ -1,111 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from positional import positional - -from keystoneclient import access -from keystoneclient import base - - -def _calc_id(token): - if isinstance(token, access.AccessInfo): - return token.auth_token - - return base.getid(token) - - -class TokenManager(object): - """Manager class for manipulating Identity tokens.""" - - def __init__(self, client): - self._client = client - - def revoke_token(self, token): - """Revoke a token. - - :param token: The token to be revoked. - :type token: str or :class:`keystoneclient.access.AccessInfo` - - """ - token_id = _calc_id(token) - headers = {'X-Subject-Token': token_id} - return self._client.delete('/auth/tokens', headers=headers) - - @positional.method(0) - def get_revoked(self, audit_id_only=False): - """Get revoked tokens list. - - :param bool audit_id_only: If true, the server is requested to not send - token IDs, but only audit IDs instead. - **New in version 2.2.0.** - :returns: A dict containing ``signed`` which is a CMS formatted string - if the server signed the response. If `audit_id_only` is true - then the response may be a dict containing ``revoked`` which - is the list of token audit IDs and expiration times. - :rtype: dict - - """ - path = '/auth/tokens/OS-PKI/revoked' - if audit_id_only: - path += '?audit_id_only' - resp, body = self._client.get(path) - return body - - @positional.method(1) - def get_token_data(self, token, include_catalog=True, allow_expired=False): - """Fetch the data about a token from the identity server. - - :param str token: The ID of the token to be fetched. - :param bool include_catalog: Whether the service catalog should be - included in the response. - :param allow_expired: If True the token will be validated and returned - if it has already expired. - - :rtype: dict - - """ - headers = {'X-Subject-Token': token} - flags = [] - - url = '/auth/tokens' - - if not include_catalog: - flags.append('nocatalog') - if allow_expired: - flags.append('allow_expired=1') - - if flags: - url = '%s?%s' % (url, '&'.join(flags)) - - resp, body = self._client.get(url, headers=headers) - return body - - @positional.method(1) - def validate(self, token, include_catalog=True, allow_expired=False): - """Validate a token. - - :param token: The token to be validated. - :type token: str or :class:`keystoneclient.access.AccessInfo` - :param include_catalog: If False, the response is requested to not - include the catalog. - :param allow_expired: If True the token will be validated and returned - if it has already expired. - :type allow_expired: bool - - :rtype: :class:`keystoneclient.access.AccessInfoV3` - - """ - token_id = _calc_id(token) - body = self.get_token_data(token_id, - include_catalog=include_catalog, - allow_expired=allow_expired) - return access.AccessInfo.factory(auth_token=token_id, body=body) diff --git a/keystoneclient/v3/users.py b/keystoneclient/v3/users.py deleted file mode 100644 index 31cad395..00000000 --- a/keystoneclient/v3/users.py +++ /dev/null @@ -1,300 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# Copyright 2011 Nebula, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from debtcollector import renames -from positional import positional - -from keystoneclient import base -from keystoneclient import exceptions -from keystoneclient.i18n import _ - - -class User(base.Resource): - """Represents an Identity user. - - Attributes: - * id: a uuid that identifies the user - - """ - - pass - - -class UserManager(base.CrudManager): - """Manager class for manipulating Identity users.""" - - resource_class = User - collection_key = 'users' - key = 'user' - - def _require_user_and_group(self, user, group): - if not (user and group): - msg = _('Specify both a user and a group') - raise exceptions.ValidationError(msg) - - @renames.renamed_kwarg('project', 'default_project', version='1.7.0', - removal_version='2.0.0') - @positional(1, enforcement=positional.WARN) - def create(self, name, domain=None, project=None, password=None, - email=None, description=None, enabled=True, - default_project=None, **kwargs): - """Create a user. - - :param str name: the name of the user. - :param domain: the domain of the user. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: the default project of the user. - (deprecated, see warning below) - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param str password: the password for the user. - :param str email: the email address of the user. - :param str description: a description of the user. - :param bool enabled: whether the user is enabled. - :param default_project: the default project of the user. - :type default_project: str or - :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to the - server. - - :returns: the created user returned from server. - :rtype: :class:`keystoneclient.v3.users.User` - - .. warning:: - - The project argument is deprecated as of the 1.7.0 release in favor - of default_project and may be removed in the 2.0.0 release. - - If both default_project and project is provided, the default_project - will be used. - - """ - default_project_id = base.getid(default_project) or base.getid(project) - user_data = base.filter_none(name=name, - domain_id=base.getid(domain), - default_project_id=default_project_id, - password=password, - email=email, - description=description, - enabled=enabled, - **kwargs) - - return self._post('/users', {'user': user_data}, 'user', - log=not bool(password)) - - @renames.renamed_kwarg('project', 'default_project', version='1.7.0', - removal_version='2.0.0') - @positional(enforcement=positional.WARN) - def list(self, project=None, domain=None, group=None, default_project=None, - **kwargs): - """List users. - - :param project: the default project of the users to be filtered on. - (deprecated, see warning below) - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param domain: the domain of the users to be filtered on. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param group: the group in which the users are member of. - :type group: str or :class:`keystoneclient.v3.groups.Group` - :param default_project: the default project of the users to be filtered - on. - :type default_project: str or - :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will filter users on. - - :returns: a list of users. - :rtype: list of :class:`keystoneclient.v3.users.User`. - - .. warning:: - - The project argument is deprecated as of the 1.7.0 release in favor - of default_project and may be removed in the 2.0.0 release. - - If both default_project and project is provided, the default_project - will be used. - - """ - default_project_id = base.getid(default_project) or base.getid(project) - if group: - base_url = '/groups/%s' % base.getid(group) - else: - base_url = None - - return super(UserManager, self).list( - base_url=base_url, - domain_id=base.getid(domain), - default_project_id=default_project_id, - **kwargs) - - def get(self, user): - """Retrieve a user. - - :param user: the user to be retrieved from the server. - :type user: str or :class:`keystoneclient.v3.users.User` - - :returns: the specified user returned from server. - :rtype: :class:`keystoneclient.v3.users.User` - - """ - return super(UserManager, self).get( - user_id=base.getid(user)) - - @renames.renamed_kwarg('project', 'default_project', version='1.7.0', - removal_version='2.0.0') - @positional(enforcement=positional.WARN) - def update(self, user, name=None, domain=None, project=None, password=None, - email=None, description=None, enabled=None, - default_project=None, **kwargs): - """Update a user. - - :param user: the user to be updated on the server. - :type user: str or :class:`keystoneclient.v3.users.User` - :param str name: the new name of the user. - :param domain: the new domain of the user. - :type domain: str or :class:`keystoneclient.v3.domains.Domain` - :param project: the new default project of the user. - (deprecated, see warning below) - :type project: str or :class:`keystoneclient.v3.projects.Project` - :param str password: the new password of the user. - :param str email: the new email of the user. - :param str description: the newdescription of the user. - :param bool enabled: whether the user is enabled. - :param default_project: the new default project of the user. - :type default_project: str or - :class:`keystoneclient.v3.projects.Project` - :param kwargs: any other attribute provided will be passed to server. - - :returns: the updated user returned from server. - :rtype: :class:`keystoneclient.v3.users.User` - - .. warning:: - - The project argument is deprecated as of the 1.7.0 release in favor - of default_project and may be removed in the 2.0.0 release. - - If both default_project and project is provided, the default_project - will be used. - - """ - default_project_id = base.getid(default_project) or base.getid(project) - user_data = base.filter_none(name=name, - domain_id=base.getid(domain), - default_project_id=default_project_id, - password=password, - email=email, - description=description, - enabled=enabled, - **kwargs) - - return self._update('/users/%s' % base.getid(user), - {'user': user_data}, - 'user', - method='PATCH', - log=False) - - def update_password(self, old_password, new_password): - """Update the password for the user the token belongs to. - - :param str old_password: the user's old password - :param str new_password: the user's new password - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - if not (old_password and new_password): - msg = _('Specify both the current password and a new password') - raise exceptions.ValidationError(msg) - - if old_password == new_password: - msg = _('Old password and new password must be different.') - raise exceptions.ValidationError(msg) - - params = {'user': {'password': new_password, - 'original_password': old_password}} - - base_url = '/users/%s/password' % self.client.user_id - - return self._update(base_url, params, method='POST', log=False) - - def add_to_group(self, user, group): - """Add the specified user as a member of the specified group. - - :param user: the user to be added to the group. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the group to put the user in. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - self._require_user_and_group(user, group) - - base_url = '/groups/%s' % base.getid(group) - return super(UserManager, self).put( - base_url=base_url, - user_id=base.getid(user)) - - def check_in_group(self, user, group): - """Check if the specified user is a member of the specified group. - - :param user: the user to be verified in the group. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the group to check the user in. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - self._require_user_and_group(user, group) - - base_url = '/groups/%s' % base.getid(group) - return super(UserManager, self).head( - base_url=base_url, - user_id=base.getid(user)) - - def remove_from_group(self, user, group): - """Remove the specified user from the specified group. - - :param user: the user to be removed from the group. - :type user: str or :class:`keystoneclient.v3.users.User` - :param group: the group to remove the user from. - :type group: str or :class:`keystoneclient.v3.groups.Group` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - self._require_user_and_group(user, group) - - base_url = '/groups/%s' % base.getid(group) - return super(UserManager, self).delete( - base_url=base_url, - user_id=base.getid(user)) - - def delete(self, user): - """Delete a user. - - :param user: the user to be deleted on the server. - :type user: str or :class:`keystoneclient.v3.users.User` - - :returns: Response object with 204 status. - :rtype: :class:`requests.models.Response` - - """ - return super(UserManager, self).delete( - user_id=base.getid(user)) diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml b/releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml deleted file mode 100644 index 6a3f6cad..00000000 --- a/releasenotes/notes/Add-allow-expired-flag-to-validate-25b8914f4deb359b.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Added a ``allow_expired`` argument to ``validate`` and ``get_token_data`` - in `keystoneclient.v3.tokens`. Setting this to ``True``, allos for a token - validation query to fetch expired tokens. diff --git a/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml b/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml deleted file mode 100644 index e6ae2b08..00000000 --- a/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - Added support for ``domain configs``. A user can now - upload domain specific configurations to keytone - using the client. See ``client.domain_configs.create``, - ``client.domain_configs.delete``, ``client.domain_configs.get`` - and ``client.domain_configs.update``. diff --git a/releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml b/releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml deleted file mode 100644 index 2699a7f5..00000000 --- a/releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Added ability to filter on multiple values with the same parameter key. - For example, we can now filter on user names that contain both ``test`` and - ``user`` using ``keystone.users.list(name__contains=['test', 'user'])``. diff --git a/releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml b/releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml deleted file mode 100644 index e9c1c9c3..00000000 --- a/releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -fixes: - - > - [`bug 1616105 `_] - Only log the response body when the ``Content-Type`` header is set to - ``application/json``. This avoids logging large binary objects (such as - images). Other ``Content-Type`` will not be logged. Additional - ``Content-Type`` strings can be added as required. diff --git a/releasenotes/notes/bug-1641674-4862454115265e76.yaml b/releasenotes/notes/bug-1641674-4862454115265e76.yaml deleted file mode 100644 index 19c8ecc3..00000000 --- a/releasenotes/notes/bug-1641674-4862454115265e76.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -prelude: > - Keystone Client now supports endpoint group filtering. -features: - - | - Support for handling the relationship between endpoint groups and projects - has been added. It is now possible to list, associate, check and - disassociate endpoint groups that have access to a project. diff --git a/releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml b/releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml deleted file mode 100644 index 5d066e90..00000000 --- a/releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - | - The ``X-Service-Token`` header value is now properly masked, and is - displayed as a hash value, in the log. diff --git a/releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml b/releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml deleted file mode 100644 index fd08a910..00000000 --- a/releasenotes/notes/deprecated_auth-d2a2bf537bdb88d3.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -deprecations: - - > - [`blueprint deprecate-to-ksa `_] - Several modules related to authentication in keystoneclient have been - deprecated in favor of [`keystoneauth `_] - These modules include: ``keystoneclient.session``, ``keystoneclient.adapter``, - ``keystoneclient.httpclient``, ``keystoneclient.auth.base``, - ``keystoneclient.auth.cli``, ``keystoneclient.auth.conf``, - ``keystoneclient.auth.identity.base``, and ``keystoneclient.auth.token_endpoint``. - Tips for migrating to `keystoneauth` have been - [`documented `_]. diff --git a/releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml b/releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml deleted file mode 100644 index e00ccae1..00000000 --- a/releasenotes/notes/implied_roles-ea39d3c3d998d482.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - support for implied roles in v3 API. diff --git a/releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml b/releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml deleted file mode 100644 index e95c939b..00000000 --- a/releasenotes/notes/ksc_2.1.0-739ded9c4c3f8aaa.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -fixes: - - > - [`bug 1462694 `_] - Add support for `include_subtree` in list_role_assignments. - - > - [`bug 1526686 `_] - Replace textwrap with faster code in cms functions. - - > - [`bug 1457702 `_] - Change default endpoint to public for keystone v3. - - > - [`bug 1520244 `_] - Support `truncated` flag returned from server. -other: - - > - Support v2 parameters for the v3 service create method. diff --git a/releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml b/releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml deleted file mode 100644 index 499306a4..00000000 --- a/releasenotes/notes/list_role_assignment_names-7e1b7eb8c2d22d7c.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - > - [`bug 1479569 `_] - With the ``include_names`` parameter set to True the names of the role assignments - are returned with the entities IDs. (GET /role_assignments?include_names=True) diff --git a/releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml b/releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml deleted file mode 100644 index 01ebe3e1..00000000 --- a/releasenotes/notes/remove-credentials-data-46ab3c3c248047cf.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -prelude: > - The ``data`` argument for creating and updating credentials has - been removed. -other: - - The ``data`` argument for creating and updating credentials was - deprecated in the 1.7.0 release. It has been replaced by the - ``blob`` argument. diff --git a/releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml b/releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml deleted file mode 100644 index cd9859cc..00000000 --- a/releasenotes/notes/remove-middleware-eef8c40117b465aa.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -prelude: > - keystoneclient.middleware has been removed. -critical: - - > - [`bug 1449066 `_] - The `keystoneclient.middleware` module has been removed in favor of the - keystonemiddleware library. The aforementioned module has been deprecated - since keystoneclient v0.10.0 which was included in the Juno release - of OpenStack. diff --git a/releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml b/releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml deleted file mode 100644 index 24a25d7e..00000000 --- a/releasenotes/notes/remove_apiclient_exceptions-0cd5c8d16aa09a22.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -other: - - > - Removed `keystoneclient.apiclient.exceptions`. This file was deprecated - in v0.7.1 and has now been replaced by `keystoneclient.exceptions`. diff --git a/releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml b/releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml deleted file mode 100644 index 1fbe6b72..00000000 --- a/releasenotes/notes/remove_apiclient_exceptions-6580003a885db286.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -prelude: > - keystoneclient.apiclient has been removed. -critical: - - > - [`bug 1526651 `_] - The `keystoneclient.apiclient` module has been removed in favor of - `keystoneclient.exceptions`. The aforementioned module has been deprecated - since keystoneclient v0.7.1 which was inclued in the Juno release - of OpenStack. diff --git a/releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml b/releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml deleted file mode 100644 index c1428096..00000000 --- a/releasenotes/notes/remove_cli-d2c4435ba6a09b79.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -prelude: > - The ``keystone`` CLI has been removed. -other: - - The ``keystone`` CLI has been removed, using the ``openstack`` - CLI is recommended. This feature has been deprecated since the - Liberty release of Keystone. diff --git a/releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml b/releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml deleted file mode 100644 index 61b9d17a..00000000 --- a/releasenotes/notes/removed-generic-client-ff505b2b01bc9302.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - Deprecate the `keystoneclient.generic` client. This client used to be able - to determine available API versions and some basics around installed - extensions however the APIs were never upgraded for the v3 API. It doesn't - seem to be used in the openstack ecosystem. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index cc58e398..00000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,285 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# keystoneclient Release Notes documentation build configuration file, created -# by sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'keystoneclient Release Notes' -copyright = u'2015, Keystone Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -import pbr.version -keystone_version = pbr.version.VersionInfo('keystoneclient') -# The full version, including alpha/beta/rc tags. -release = keystone_version.version_string_with_vcs() -# The short X.Y version. -version = keystone_version.canonical_version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'KeystoneClientReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'keystoneclientReleaseNotes.tex', - u'keystoneclient Release Notes Documentation', - u'Keystone Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'keystoneclientreleasenotes', - u'keystoneclient Release Notes Documentation', - [u'Keystone Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'keystoneclientReleaseNotes', - u'keystoneclient Release Notes Documentation', - u'Keystone Developers', 'keystoneclientReleaseNotes', - 'Python bindings for the OpenStack Identity service.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] - -# -- Options for openstackdocstheme ------------------------------------------- -repository_name = 'openstack/python-keystoneclient' -bug_project = 'python-keystoneclient' -bug_tag = '' diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 10af6372..00000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -============================== - keystoneclient Release Notes -============================== - -.. toctree:: - :maxdepth: 1 - - unreleased - ocata - newton - mitaka diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst deleted file mode 100644 index e5456096..00000000 --- a/releasenotes/source/mitaka.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Mitaka Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/mitaka diff --git a/releasenotes/source/newton.rst b/releasenotes/source/newton.rst deleted file mode 100644 index 7b7d7352..00000000 --- a/releasenotes/source/newton.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= - Newton Series Release Notes -============================= - -.. release-notes:: - :branch: origin/stable/newton diff --git a/releasenotes/source/ocata.rst b/releasenotes/source/ocata.rst deleted file mode 100644 index 9515f6cf..00000000 --- a/releasenotes/source/ocata.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================ - Ocata Series Release Notes -============================ - -.. release-notes:: - :branch: origin/stable/ocata diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index cd22aabc..00000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. release-notes:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 21add6b2..00000000 --- a/requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr!=2.1.0,>=2.0.0 # Apache-2.0 - -debtcollector>=1.2.0 # Apache-2.0 -keystoneauth1>=3.0.1 # Apache-2.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 -positional>=1.1.1 # Apache-2.0 -requests>=2.14.2 # Apache-2.0 -six>=1.9.0 # MIT -stevedore>=1.20.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8995a9cd..00000000 --- a/setup.cfg +++ /dev/null @@ -1,69 +0,0 @@ -[metadata] -name = python-keystoneclient -summary = Client Library for OpenStack Identity -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://docs.openstack.org/python-keystoneclient/latest/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 - -[files] -packages = - keystoneclient - -[entry_points] -keystoneclient.auth.plugin = - password = keystoneclient.auth.identity.generic:Password - token = keystoneclient.auth.identity.generic:Token - admin_token = keystoneclient.auth.token_endpoint:Token - v2password = keystoneclient.auth.identity.v2:Password - v2token = keystoneclient.auth.identity.v2:Token - v3password = keystoneclient.auth.identity.v3:Password - v3token = keystoneclient.auth.identity.v3:Token - v3oidcpassword = keystoneclient.contrib.auth.v3.oidc:OidcPassword - v3unscopedsaml = keystoneclient.contrib.auth.v3.saml2:Saml2UnscopedToken - v3scopedsaml = keystoneclient.contrib.auth.v3.saml2:Saml2ScopedToken - v3unscopedadfs = keystoneclient.contrib.auth.v3.saml2:ADFSUnscopedToken - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 -warning-is-error = 1 - -[pbr] -autodoc_tree_index_modules = True -autodoc_tree_excludes = - setup.py - keystoneclient/tests/ - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = keystoneclient/locale -domain = keystoneclient - -[update_catalog] -domain = keystoneclient -output_dir = keystoneclient/locale -input_file = keystoneclient/locale/keystoneclient.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = keystoneclient/locale/keystoneclient.pot - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d8443..00000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 10c49e5a..00000000 --- a/test-requirements.txt +++ /dev/null @@ -1,26 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking<0.11,>=0.10.0 -flake8-docstrings==0.2.1.post1 # MIT - -coverage!=4.4,>=4.0 # Apache-2.0 -fixtures>=3.0.0 # Apache-2.0/BSD -keyring>=5.5.1 # MIT/PSF -lxml!=3.7.0,>=2.3 # BSD -mock>=2.0 # BSD -oauthlib>=0.6 # BSD -openstackdocstheme>=1.11.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -reno!=2.3.1,>=1.8.0 # Apache-2.0 -requests-mock>=1.1 # Apache-2.0 -sphinx>=1.6.2 # BSD -tempest>=16.1.0 # Apache-2.0 -testrepository>=0.0.18 # Apache-2.0/BSD -testresources>=0.2.4 # Apache-2.0/BSD -testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT - -# Bandit security code scanner -bandit>=1.1.0 # Apache-2.0 diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index e61b63a8..00000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. - -CONSTRAINTS_FILE="$1" -shift 1 - -set -e - -# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get -# published to logs.openstack.org for easy debugging. -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ "$CONSTRAINTS_FILE" != http* ]]; then - CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE" -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile" - -pip install -c"$localfile" openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints "$localfile" -- "$CLIENT_NAME" - -pip install -c"$localfile" -U "$@" -exit $? diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 08ba9624..00000000 --- a/tox.ini +++ /dev/null @@ -1,74 +0,0 @@ -[tox] -minversion = 2.0 -skipsdist = True -envlist = py35,py27,pep8,releasenotes - -[testenv] -usedevelop = True -install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -setenv = VIRTUAL_ENV={envdir} - BRANCH_NAME=master - CLIENT_NAME=python-keystoneclient - OS_STDOUT_NOCAPTURE=False - OS_STDERR_NOCAPTURE=False - -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = find . -type f -name "*.pyc" -delete - python setup.py testr --slowest --testr-args='{posargs}' -whitelist_externals = find - -[testenv:pep8] -commands = - flake8 - bandit -r keystoneclient -x tests -n5 - -[testenv:bandit] -# NOTE(browne): This is required for the integration test job of the bandit -# project. Please do not remove. -commands = bandit -r keystoneclient -x tests -n5 - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='{posargs}' - coverage report - -[testenv:debug] -commands = oslo_debug_helper -t keystoneclient/tests {posargs} - -[testenv:functional] -setenv = {[testenv]setenv} - OS_TEST_PATH=./keystoneclient/tests/functional -passenv = OS_* - -[flake8] -# D100: Missing docstring in public module -# D101: Missing docstring in public class -# D102: Missing docstring in public method -# D103: Missing docstring in public function -# D104: Missing docstring in public package -# D203: 1 blank line required before class docstring (deprecated in pep257) -ignore = D100,D101,D102,D103,D104,D203 -show-source = True -exclude = .venv,.tox,dist,doc,*egg,build - -[testenv:docs] -commands= - python setup.py build_sphinx - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html - -[hacking] -import_exceptions = - keystoneclient.i18n - -[testenv:bindep] -# Do not install any requirements. We want this to be fast and work even if -# system dependencies are missing, since it's used to tell you what system -# dependencies are missing! This also means that bindep must be installed -# separately, outside of the requirements files. -deps = bindep -commands = bindep test