diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..430e5a33 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,90 @@ +# 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/ext/__init__.py b/doc/ext/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/doc/ext/apidoc.py b/doc/ext/apidoc.py new file mode 100644 index 00000000..60ad23e8 --- /dev/null +++ b/doc/ext/apidoc.py @@ -0,0 +1,46 @@ +# 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. + +# NOTE(blk-u): Uncomment the [pbr] section in setup.cfg and remove this +# Sphinx extension when https://launchpad.net/bugs/1260495 is fixed. + +import os.path as path + +from sphinx import apidoc + + +# NOTE(blk-u): pbr will run Sphinx multiple times when it generates +# documentation. Once for each builder. To run this extension we use the +# 'builder-inited' hook that fires at the beginning of a Sphinx build. +# We use ``run_already`` to make sure apidocs are only generated once +# even if Sphinx is run multiple times. +run_already = False + + +def run_apidoc(app): + global run_already + if run_already: + return + run_already = True + + package_dir = path.abspath(path.join(app.srcdir, '..', '..', + 'keystoneclient')) + source_dir = path.join(app.srcdir, 'api') + apidoc.main(['apidoc', package_dir, '-f', + '-H', 'keystoneclient Modules', + '-o', source_dir]) + + +def setup(app): + app.connect('builder-inited', run_apidoc) diff --git a/doc/source/authentication-plugins.rst b/doc/source/authentication-plugins.rst new file mode 100644 index 00000000..5afc0bc2 --- /dev/null +++ b/doc/source/authentication-plugins.rst @@ -0,0 +1,237 @@ +====================== +Authentication Plugins +====================== + +Introduction +============ + +Authentication plugins provide a generic means by which to extend the +authentication mechanisms known to OpenStack clients. + +In the vast majority of cases the authentication plugins used will be those +written for use with the OpenStack Identity Service (Keystone), however this is +not the only possible case, and the mechanisms by which authentication plugins +are used and implemented should be generic enough to cover completely +customized authentication solutions. + +The subset of authentication plugins intended for use with an OpenStack +Identity server (such as Keystone) are called Identity Plugins. + + +Available Plugins +================= + +Keystoneclient ships with a number of plugins and particularly Identity +Plugins. + +V2 Identity Plugins +------------------- + +Standard V2 identity plugins are defined in the module: +:py:mod:`keystoneclient.auth.identity.v2` + +They include: + +- :py:class:`~keystoneclient.auth.identity.v2.Password`: Authenticate against + a V2 identity service using a username and password. +- :py:class:`~keystoneclient.auth.identity.v2.Token`: Authenticate against a + V2 identity service using an existing token. + +V2 identity plugins must use an auth_url that points to the root of a V2 +identity server URL, i.e.: `http://hostname:5000/v2.0`. + +V3 Identity Plugins +------------------- + +Standard V3 identity plugins are defined in the module +:py:mod:`keystoneclient.auth.identity.v3`. + +V3 Identity plugins are slightly different from their V2 counterparts as a V3 +authentication request can contain multiple authentication methods. To handle +this V3 defines a number of different +:py:class:`~keystoneclient.auth.identity.v3.AuthMethod` classes: + +- :py:class:`~keystoneclient.auth.identity.v3.PasswordMethod`: Authenticate + against a V3 identity service using a username and password. +- :py:class:`~keystoneclient.auth.identity.v3.TokenMethod`: Authenticate against + a V2 identity service using an existing token. + +The :py:class:`~keystoneclient.auth.identity.v3.AuthMethod` objects are then +passed to the :py:class:`~keystoneclient.auth.identity.v3.Auth` plugin:: + + >>> from keystoneclient import session + >>> from keystoneclient.auth.identity import v3 + >>> password = v3.PasswordMethod(username='user', + ... password='password') + >>> auth = v3.Auth(auth_url='http://my.keystone.com:5000/v3', + ... auth_methods=[password], + ... project_id='projectid') + >>> sess = session.Session(auth=auth) + +As in the majority of cases you will only want to use one +:py:class:`~keystoneclient.auth.identity.v3.AuthMethod` there are also helper +authentication plugins for the various +:py:class:`~keystoneclient.auth.identity.v3.AuthMethod` which can be used more +like the V2 plugins: + +- :py:class:`~keystoneclient.auth.identity.v3.Password`: Authenticate using + only a :py:class:`~keystoneclient.auth.identity.v3.PasswordMethod`. +- :py:class:`~keystoneclient.auth.identity.v3.Token`: Authenticate using only a + :py:class:`~keystoneclient.auth.identity.v3.TokenMethod`. + +:: + + >>> auth = v3.Password(auth_url='http://my.keystone.com:5000/v3', + ... username='username', + ... password='password', + ... project_id='projectid') + >>> sess = session.Session(auth=auth) + +This will have exactly the same effect as using the single +:py:class:`~keystoneclient.auth.identity.v3.PasswordMethod` above. + +V3 identity plugins must use an auth_url that points to the root of a V3 +identity server URL, i.e.: `http://hostname:5000/v3`. + +Version Independent Identity Plugins +------------------------------------ + +Standard version independent identity plugins are defined in the module +:py:mod:`keystoneclient.auth.identity.generic`. + +For the cases of plugins that exist under both the identity V2 and V3 APIs +there is an abstraction to allow the plugin to determine which of the V2 and V3 +APIs are supported by the server and use the most appropriate API. + +These plugins are: + +- :py:class:`~keystoneclient.auth.identity.generic.Password`: Authenticate + using a user/password against either v2 or v3 API. +- :py:class:`~keystoneclient.auth.identity.generic.Token`: Authenticate using + an existing token against either v2 or v3 API. + +These plugins work by first querying the identity server to determine available +versions and so the `auth_url` used with the plugins should point to the base +URL of the identity server to use. If the `auth_url` points to either a V2 or +V3 endpoint it will restrict the plugin to only working with that version of +the API. + +Simple Plugins +-------------- + +In addition to the Identity plugins a simple plugin that will always use the +same provided token and endpoint is available. This is useful in situations +where you have an ``ADMIN_TOKEN`` or in testing when you specifically know the +endpoint you want to communicate with. + +It can be found at :py:class:`keystoneclient.auth.token_endpoint.Token`. + + +V3 OAuth 1.0a Plugins +--------------------- + +There also exists a plugin for OAuth 1.0a authentication. We provide a helper +authentication plugin at: +:py:class:`~keystoneclient.v3.contrib.oauth1.auth.OAuth`. +The plugin requires the OAuth consumer's key and secret, as well as the OAuth +access token's key and secret. For example:: + + >>> from keystoneclient.v3.contrib.oauth1 import auth + >>> from keystoneclient import session + >>> from keystoneclient.v3 import client + >>> a = auth.OAuth('http://my.keystone.com:5000/v3', + ... consumer_key=consumer_id, + ... consumer_secret=consumer_secret, + ... access_key=access_token_key, + ... access_secret=access_token_secret) + >>> s = session.Session(auth=a) + + +Loading Plugins by Name +======================= + +In auth_token middleware and for some service to service communication it is +possible to specify a plugin to load via name. The authentication options that +are available are then specific to the plugin that you specified. Currently the +authentication plugins that are available in `keystoneclient` are: + +- password: :py:class:`keystoneclient.auth.identity.generic.Password` +- token: :py:class:`keystoneclient.auth.identity.generic.Token` +- v2password: :py:class:`keystoneclient.auth.identity.v2.Password` +- v2token: :py:class:`keystoneclient.auth.identity.v2.Token` +- v3password: :py:class:`keystoneclient.auth.identity.v3.Password` +- v3token: :py:class:`keystoneclient.auth.identity.v3.Token` + + +Creating Authentication Plugins +=============================== + +Creating an Identity Plugin +--------------------------- + +If you have implemented a new authentication mechanism into the Identity +service then you will be able to reuse a lot of the infrastructure available +for the existing Identity mechanisms. As the V2 identity API is essentially +frozen, it is expected that new plugins are for the V3 API. + +To implement a new V3 plugin that can be combined with others you should +implement the base :py:class:`keystoneclient.auth.identity.v3.AuthMethod` class +and implement the +:py:meth:`~keystoneclient.auth.identity.v3.AuthMethod.get_auth_data` function. +If your Plugin cannot be used in conjunction with existing +:py:class:`keystoneclient.auth.identity.v3.AuthMethod` then you should just +override :py:class:`keystoneclient.auth.identity.v3.Auth` directly. + +The new :py:class:`~keystoneclient.auth.identity.v3.AuthMethod` should take all +the required parameters via +:py:meth:`~keystoneclient.auth.identity.v3.AuthMethod.__init__` and return from +:py:meth:`~keystoneclient.auth.identity.v3.AuthMethod.get_auth_data` a tuple +with the unique identifier of this plugin (e.g. *password*) and a dictionary +containing the payload of values to send to the authentication server. The +session, calling auth object and request headers are also passed to this +function so that the plugin may use or manipulate them. + +You should also provide a class that inherits from +:py:class:`keystoneclient.auth.identity.v3.Auth` with an instance of your new +:py:class:`~keystoneclient.auth.identity.v3.AuthMethod` as the `auth_methods` +parameter to :py:class:`keystoneclient.auth.identity.v3.Auth`. + +By convention (and like above) these are named `PluginType` and +`PluginTypeMethod` (for example +:py:class:`~keystoneclient.auth.identity.v3.Password` and +:py:class:`~keystoneclient.auth.identity.v3.PasswordMethod`). + + +Creating a Custom Plugin +------------------------ + +To implement an entirely new plugin you should implement the base class +:py:class:`keystoneclient.auth.base.BaseAuthPlugin` and provide the +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.get_endpoint`, +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.get_token` and +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.invalidate` functions. + +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.get_token` is called to +retrieve the string token from a plugin. It is intended that a plugin will +cache a received token and so if the token is still valid then it should be +re-used rather than fetching a new one. A session object is provided with which +the plugin can contact it's server. (Note: use `authenticated=False` when +making those requests or it will end up being called recursively). The return +value should be the token as a string. + +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.get_endpoint` is called to +determine a base URL for a particular service's requests. The keyword arguments +provided to the function are those that are given by the `endpoint_filter` +variable in :py:meth:`keystoneclient.session.Session.request`. A session object +is also provided so that the plugin may contact an external source to determine +the endpoint. Again this will be generally be called once per request and so +it is up to the plugin to cache these responses if appropriate. The return +value should be the base URL to communicate with. + +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.invalidate` should also be +implemented to clear the current user credentials so that on the next +:py:meth:`~keystoneclient.auth.base.BaseAuthPlugin.get_token` call a new token +can be retrieved. + +The most simple example of a plugin is the +:py:class:`keystoneclient.auth.token_endpoint.Token` plugin. diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 00000000..f256fd46 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,240 @@ +# -*- coding: utf-8 -*- +# +# 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__), + '..', '..'))) + +# NOTE(blk-u): Path for our Sphinx extension, remove when +# https://launchpad.net/bugs/1260495 is fixed. +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', + 'oslosphinx', + # NOTE(blk-u): Uncomment the [pbr] section in setup.cfg and + # remove this Sphinx extension when + # https://launchpad.net/bugs/1260495 is fixed. + 'ext.apidoc', + ] + +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 = [] + +# Grouping the document tree for man pages. +# List of tuples 'sourcefile', 'target', 'title', 'Authors name', 'manual' + +man_pages = [ + ('man/keystone', 'keystone', 'Client for OpenStack Identity API', + ['OpenStack Contributors'], 1), +] + +# -- 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' + +# 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. +git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1" +html_last_updated_fmt = os.popen(git_cmd).read() + +# 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 + +intersphinx_mapping = { + 'python': ('http://docs.python.org/', None), + 'osloconfig': ('http://docs.openstack.org/developer/oslo.config/', None), +} diff --git a/doc/source/images/graphs_authComp.svg b/doc/source/images/graphs_authComp.svg new file mode 100644 index 00000000..6be629c1 --- /dev/null +++ b/doc/source/images/graphs_authComp.svg @@ -0,0 +1,48 @@ + + + + + + +AuthComp + + +AuthComp + +Auth +Component + + + +AuthComp->Reject + + +Reject +Unauthenticated +Requests + + +Service + +OpenStack +Service + + +AuthComp->Service + + +Forward +Authenticated +Requests + + + +Start->AuthComp + + + + + diff --git a/doc/source/images/graphs_authCompDelegate.svg b/doc/source/images/graphs_authCompDelegate.svg new file mode 100644 index 00000000..4788829a --- /dev/null +++ b/doc/source/images/graphs_authCompDelegate.svg @@ -0,0 +1,53 @@ + + + + + + +AuthCompDelegate + + +AuthComp + +Auth +Component + + + +AuthComp->Reject + + +Reject Requests +Indicated by the Service + + +Service + +OpenStack +Service + + +AuthComp->Service + + +Forward Requests +with Identiy Status + + +Service->AuthComp + + +Send Response OR +Reject Message + + + +Start->AuthComp + + + + + diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 00000000..9d931cab --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,49 @@ +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), and a command-line script (installed as +:doc:`keystone `). + +Contents: + +.. toctree:: + :maxdepth: 1 + + man/keystone + using-api-v3 + using-sessions + authentication-plugins + 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`: http://docs.openstack.org/developer/keystone/ +.. _`WSGI Middleware`: http://docs.openstack.org/developer/keystonemiddleware/ + +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: http://docs.openstack.org/infra/manual/developers.html#development-workflow + +Run tests with ``python setup.py test``. + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/source/man/keystone.rst b/doc/source/man/keystone.rst new file mode 100644 index 00000000..10d9d93c --- /dev/null +++ b/doc/source/man/keystone.rst @@ -0,0 +1,158 @@ +============================================================== +:program:`keystone` command line utility (pending deprecation) +============================================================== + +.. program:: keystone +.. highlight:: bash + +SYNOPSIS +======== + +:program:`keystone` [options] [command-options] + +:program:`keystone help` + +:program:`keystone help` + + +DESCRIPTION +=========== + +.. WARNING:: + + The :program:`keystone` command line utility is pending deprecation. The + `OpenStackClient unified command line utility + `_ should be + used instead. The :program:`keystone` command line utility only supports V2 + of the Identity API whereas the OSC program supports both V2 and V3. + +The :program:`keystone` command line utility interacts with services providing +OpenStack Identity API (e.g. Keystone). + +To communicate with the API, you will need to be authenticated - and the +:program:`keystone` provides multiple options for this. + +While bootstrapping Keystone the authentication is accomplished with a +shared secret token and the location of the Identity API endpoint. The +shared secret token is configured in keystone.conf as "admin_token". + +You can specify those values on the command line with :option:`--os-token` +and :option:`--os-endpoint`, or set them in environment variables: + +.. envvar:: OS_SERVICE_TOKEN + + Your Keystone administrative token + +.. envvar:: OS_SERVICE_ENDPOINT + + Your Identity API endpoint + +The command line options will override any environment variables set. + +If you already have accounts, you can use your OpenStack username and +password. You can do this with the :option:`--os-username`, +:option:`--os-password`. + +Keystone allows a user to be associated with one or more projects which are +historically called tenants. To specify the project for which you want to +authorize against, you may optionally specify a :option:`--os-tenant-id` or +:option:`--os-tenant-name`. + +Instead of using options, it is easier to just set them as environment +variables: + +.. envvar:: OS_USERNAME + + Your Keystone username. + +.. envvar:: OS_PASSWORD + + Your Keystone password. + +.. envvar:: OS_TENANT_NAME + + Name of Keystone project. + +.. envvar:: OS_TENANT_ID + + ID of Keystone Tenant. + +.. envvar:: OS_AUTH_URL + + The OpenStack API server URL. + +.. envvar:: OS_IDENTITY_API_VERSION + + The OpenStack Identity API version. + +.. envvar:: OS_CACERT + + The location for the CA truststore (PEM formatted) for this client. + +.. envvar:: OS_CERT + + The location for the keystore (PEM formatted) containing the public + key of this client. This keystore can also optionally contain the + private key of this client. + +.. envvar:: OS_KEY + + The location for the keystore (PEM formatted) containing the private + key of this client. This value can be empty if the private key is + included in the OS_CERT file. + +For example, in Bash you'd use:: + + export OS_USERNAME=yourname + export OS_PASSWORD=yadayadayada + export OS_TENANT_NAME=myproject + export OS_AUTH_URL=http(s)://example.com:5000/v2.0/ + export OS_IDENTITY_API_VERSION=2.0 + export OS_CACERT=/etc/keystone/yourca.pem + export OS_CERT=/etc/keystone/yourpublickey.pem + export OS_KEY=/etc/keystone/yourprivatekey.pem + + +OPTIONS +======= + +To get a list of available commands and options run:: + + keystone help + +To get usage and options of a command:: + + keystone help + + +EXAMPLES +======== + +Get information about endpoint-create command:: + + keystone help endpoint-create + +View endpoints of OpenStack services:: + + keystone catalog + +Create a 'service' project:: + + keystone tenant-create --name=service + +Create service user for nova:: + + keystone user-create --name=nova \ + --tenant_id= \ + --email=nova@nothing.com + +View roles:: + + keystone role-list + + +BUGS +==== + +Keystone client is hosted in Launchpad so you can view current bugs at +https://bugs.launchpad.net/python-keystoneclient/. diff --git a/doc/source/using-api-v2.rst b/doc/source/using-api-v2.rst new file mode 100644 index 00000000..03e76e17 --- /dev/null +++ b/doc/source/using-api-v2.rst @@ -0,0 +1,117 @@ +======================= +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 +authentication data 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 keystoneclient.v2_0 import client + >>> token = '012345SECRET99TOKEN012345' + >>> endpoint = 'http://192.168.206.130:35357/v2.0' + >>> keystone = client.Client(token=token, endpoint=endpoint) + +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 keystoneclient.v2_0 import client + >>> username='adminUser' + >>> password='secreetword' + >>> tenant_name='openstackDemo' + >>> auth_url='http://192.168.206.130:5000/v2.0' + >>> keystone = client.Client(username=username, password=password, + ... tenant_name=tenant_name, auth_url=auth_url) + +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 opoenstackDemo 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 new file mode 100644 index 00000000..61b2b9d8 --- /dev/null +++ b/doc/source/using-api-v3.rst @@ -0,0 +1,140 @@ +======================= +Using the V3 Client API +======================= + +Introduction +============ + +The main concepts in the Identity v3 API are: + + * :py:mod:`~keystoneclient.v3.credentials` + * :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 +``keystoneclient.exceptions.ClientException`` (see +:py:class:`keystoneclient.openstack.common.apiclient.exceptions.ClientException`) + +Authenticating Using Sessions +============================= + +Instantiate a :py:class:`keystoneclient.v3.client.Client` using a +:py:class:`~keystoneclient.session.Session` to provide the authentication +plugin, SSL/TLS certificates, and other data:: + + >>> from keystoneclient.auth.identity import v3 + >>> from keystoneclient 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:`~keystoneclient.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 new file mode 100644 index 00000000..7d31a2d6 --- /dev/null +++ b/doc/source/using-sessions.rst @@ -0,0 +1,198 @@ +============== +Using Sessions +============== + +Introduction +============ + +The :py:class:`keystoneclient.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 keystoneclient.auth.identity import v3 + >>> from keystoneclient import session + >>> from keystoneclient.v3 import client + + >>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v2.0', + ... username='myuser', + ... password='mypassword', + ... project_id='proj') + >>> 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:`keystoneclient.auth.token_endpoint.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.