===============
The Auth System
===============

--------
TempAuth
--------

The auth system for Swift is loosely based on the auth system from the existing
Rackspace architecture -- actually from a few existing auth systems -- and is
therefore a bit disjointed. The distilled points about it are:

* The authentication/authorization part can be an external system or a
  subsystem run within Swift as WSGI middleware
* The user of Swift passes in an auth token with each request
* Swift validates each token with the external auth system or auth subsystem
  and caches the result
* The token does not change from request to request, but does expire

The token can be passed into Swift using the X-Auth-Token or the
X-Storage-Token header. Both have the same format: just a simple string
representing the token. Some auth systems use UUID tokens, some an MD5 hash of
something unique, some use "something else" but the salient point is that the
token is a string which can be sent as-is back to the auth system for
validation.

Swift will make calls to the auth system, giving the auth token to be
validated. For a valid token, the auth system responds with an overall
expiration in seconds from now. Swift will cache the token up to the expiration
time.

The included TempAuth also has the concept of admin and non-admin users
within an account.  Admin users can do anything within the account.
Non-admin users can only perform operations per container based on the
container's X-Container-Read and X-Container-Write ACLs.  Container ACLs
use the "V1" ACL syntax, which looks like this:
``name1, name2, .r:referrer1.com, .r:-bad.referrer1.com, .rlistings``
For more information on ACLs, see :mod:`swift.common.middleware.acl`.

Additionally, if the auth system sets the request environ's swift_owner key to
True, the proxy will return additional header information in some requests,
such as the X-Container-Sync-Key for a container GET or HEAD.

In addition to container ACLs, TempAuth allows account-level ACLs.  Any auth
system may use the special header ``X-Account-Access-Control`` to specify
account-level ACLs in a format specific to that auth system.  (Following the
TempAuth format is strongly recommended.)  These headers are visible and
settable only by account owners (those for whom ``swift_owner`` is true).
Behavior of account ACLs is auth-system-dependent.  In the case of TempAuth,
if an authenticated user has membership in a group which is listed in the
ACL, then the user is allowed the access level of that ACL.

Account ACLs use the "V2" ACL syntax, which is a JSON dictionary with keys
named "admin", "read-write", and "read-only".  (Note the case sensitivity.)
An example value for the ``X-Account-Access-Control`` header looks like this:
``{"admin":["a","b"],"read-only":["c"]}``  Keys may be absent (as shown).
The recommended way to generate ACL strings is as follows::

  from swift.common.middleware.acl import format_acl
  acl_data = { 'admin': ['alice'], 'read-write': ['bob', 'carol'] }
  acl_string = format_acl(version=2, acl_dict=acl_data)

Using the :func:`format_acl` method will ensure
that JSON is encoded as ASCII (using e.g. '\u1234' for Unicode).  While
it's permissible to manually send ``curl`` commands containing
``X-Account-Access-Control`` headers, you should exercise caution when
doing so, due to the potential for human error.

Within the JSON dictionary stored in ``X-Account-Access-Control``, the keys
have the following meanings:

============   ==============================================================
Access Level   Description
============   ==============================================================
read-only      These identities can read *everything* (except privileged
               headers) in the account.  Specifically, a user with read-only
               account access can get a list of containers in the account,
               list the contents of any container, retrieve any object, and
               see the (non-privileged) headers of the account, any
               container, or any object.
read-write     These identities can read or write (or create) any container.
               A user with read-write account access can create new
               containers, set any unprivileged container headers, overwrite
               objects, delete containers, etc.  A read-write user can NOT
               set account headers (or perform any PUT/POST/DELETE requests
               on the account).
admin          These identities have "swift_owner" privileges.  A user with
               admin account access can do anything the account owner can,
               including setting account headers and any privileged headers
               -- and thus granting read-only, read-write, or admin access
               to other users.
============   ==============================================================


For more details, see :mod:`swift.common.middleware.tempauth`.  For details
on the ACL format, see :mod:`swift.common.middleware.acl`.

Users with the special group ``.reseller_admin`` can operate on any account.
For an example usage please see :mod:`swift.common.middleware.tempauth`.
If a request is coming from a reseller the auth system sets the request environ
reseller_request to True. This can be used by other middlewares.

TempAuth will now allow OPTIONS requests to go through without a token.

The user starts a session by sending a ReST request to the auth system to
receive the auth token and a URL to the Swift system.

-------------
Keystone Auth
-------------

Swift is able to authenticate against OpenStack Keystone_ via the
:ref:`keystoneauth` middleware.

In order to use the ``keystoneauth`` middleware the ``auth_token``
middleware from KeystoneMiddleware_ will need to be configured.

The ``authtoken`` middleware performs the authentication token
validation and retrieves actual user authentication information. It
can be found in the KeystoneMiddleware_ distribution.

The :ref:`keystoneauth` middleware performs authorization and mapping the
Keystone roles to Swift's ACLs.

.. _KeystoneMiddleware: http://docs.openstack.org/developer/keystonemiddleware/
.. _Keystone: http://docs.openstack.org/developer/keystone/

Configuring Swift to use Keystone
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Configuring Swift to use Keystone_
is relatively straight forward.  The first
step is to ensure that you have the ``auth_token`` middleware installed. It can
either be dropped in your python path or installed via the KeystoneMiddleware_
package.

You need at first make sure you have a service endpoint of type
``object-store`` in Keystone pointing to your Swift proxy. For example
having this in your ``/etc/keystone/default_catalog.templates`` ::

  catalog.RegionOne.object_store.name = Swift Service
  catalog.RegionOne.object_store.publicURL = http://swiftproxy:8080/v1/AUTH_$(tenant_id)s
  catalog.RegionOne.object_store.adminURL = http://swiftproxy:8080/
  catalog.RegionOne.object_store.internalURL = http://swiftproxy:8080/v1/AUTH_$(tenant_id)s

On your Swift Proxy server you will want to adjust your main pipeline
and add auth_token and keystoneauth in your
``/etc/swift/proxy-server.conf`` like this ::

  [pipeline:main]
  pipeline = [....] authtoken keystoneauth proxy-logging proxy-server

add the configuration for the authtoken middleware::

  [filter:authtoken]
  paste.filter_factory = keystonemiddleware.auth_token:filter_factory
  identity_uri = http://keystonehost:35357/
  admin_tenant_name = service
  admin_user = swift
  admin_password = password
  auth_uri = http://keystonehost:5000/
  cache = swift.cache
  include_service_catalog = False

The actual values for these variables will need to be set depending on
your situation, but in short:

* ``identity_uri`` points to the Keystone Admin service. This information is
  used by the middleware to actually query Keystone about the validity of the
  authentication tokens. It is not necessary to append any Keystone API version
  number to this URI.
* The admin auth credentials (``admin_user``, ``admin_tenant_name``,
  ``admin_password``) will be used to retrieve an admin token. That
  token will be used to authorize user tokens behind the scenes.
* ``auth_uri`` should point to a Keystone service from which users may
  retrieve tokens. This value is used in the `WWW-Authenticate` header that
  auth_token sends with any denial response.
* ``cache`` is set to ``swift.cache``. This means that the middleware
  will get the Swift memcache from the request environment.
* ``include_service_catalog`` defaults to ``True`` if not set. This means
  that when validating a token, the service catalog is retrieved
  and stored in the ``X-Service-Catalog`` header. Since Swift does not
  use the ``X-Service-Catalog`` header, there is no point in getting
  the service catalog. We recommend you set ``include_service_catalog``
  to ``False``.


.. note::

    If support is required for unvalidated users (as with anonymous
    access or making capabilities requests using :ref:`discoverability`) or
    for tempurl/formpost middleware, authtoken will need
    to be configured with delay_auth_decision set to 1.

and you can finally add the keystoneauth configuration::

  [filter:keystoneauth]
  use = egg:swift#keystoneauth
  operator_roles = admin, swiftoperator

Access control using keystoneauth
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By default the only users able to perform operations (e.g. create a container)
on an account are those having a Keystone role for the corresponding Keystone
project that matches one of the roles specified in the ``operator_roles``
option.

Users who have one of the ``operator_roles`` will be able to set container ACLs
to grant other users permission to read and/or write objects in specific
containers, using ``X-Container-Read`` and ``X-Container-Write`` headers
respectively. In addition to the ACL formats described
:mod:`here <swift.common.middleware.acl>`, keystoneauth supports ACLs using the
format::

 other_project_id:other_user_id.

where ``other_project_id`` is the UUID of a Keystone project and
``other_user_id`` is the UUID of a Keystone user. This will allow the other
user to access a container provided their token is scoped on the other
project. Both ``other_project_id`` and ``other_user_id`` may be replaced with
the wildcard character ``*`` which will match any project or user respectively.

Be sure to use Keystone UUIDs rather than names in container ACLs.

.. note::

    For backwards compatibility, keystoneauth will by default grant container
    ACLs expressed as ``other_project_name:other_user_name`` (i.e. using
    Keystone names rather than UUIDs) in the special case when both the other
    project and the other user are in Keystone's default domain and the project
    being accessed is also in the default domain.

    For further information see :ref:`keystoneauth`

Users with the Keystone role defined in ``reseller_admin_role``
(``ResellerAdmin`` by default) can operate on any account. The auth system
sets the request environ reseller_request to True if a request is coming
from a user with this role. This can be used by other middlewares.

--------------
Extending Auth
--------------

TempAuth is written as wsgi middleware, so implementing your own auth is as
easy as writing new wsgi middleware, and plugging it in to the proxy server.
The KeyStone project and the Swauth project are examples of additional auth
services.

Also, see :doc:`development_auth`.