summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api-ref/source/v3/authenticate-v3.inc178
-rw-r--r--api-ref/source/v3/parameters.yaml77
-rw-r--r--api-ref/source/v3/samples/auth/requests/project-id-totp.json20
-rw-r--r--api-ref/source/v3/samples/auth/responses/auth-receipt-password.json20
-rw-r--r--api-ref/source/v3/samples/auth/responses/project-scoped-password-totp.json67
-rw-r--r--api-ref/source/v3/status.yaml8
-rw-r--r--doc/source/admin/auth-totp.rst2
-rw-r--r--doc/source/admin/authentication-mechanisms.rst1
-rw-r--r--doc/source/admin/multi-factor-authentication.rst88
-rw-r--r--doc/source/admin/resource-options.rst101
-rw-r--r--doc/source/admin/security-compliance.rst62
-rw-r--r--doc/source/user/index.rst1
-rw-r--r--doc/source/user/multi-factor-authentication.rst130
13 files changed, 698 insertions, 57 deletions
diff --git a/api-ref/source/v3/authenticate-v3.inc b/api-ref/source/v3/authenticate-v3.inc
index 45d3f58f8..6e3cc62ab 100644
--- a/api-ref/source/v3/authenticate-v3.inc
+++ b/api-ref/source/v3/authenticate-v3.inc
@@ -10,7 +10,7 @@ optionally, grants authorization on a specific project, domain, or the
deployment system.
The body of an authentication request must include a payload that
-specifies the authentication method, which is ``password`` or
+specifies the authentication methods, which are normally just ``password`` or
``token``, the credentials, and, optionally, the authorization
scope. You can scope a token to a project, domain, the deployment system, or
the token can be unscoped. You cannot scope a token to multiple scope targets.
@@ -18,6 +18,16 @@ the token can be unscoped. You cannot scope a token to multiple scope targets.
Tokens have IDs, which the Identity API returns in the
``X-Subject-Token`` response header.
+In the case of multi-factor authentication (MFA) more than one authentication
+method needs to be supplied to authenticate. As of v3.12 a failure due to MFA
+rules only partially being met will result in an auth receipt ID being returned
+in the response header ``Openstack-Auth-Receipt``, and a response body that
+details the receipt itself and the missing authentication methods. Supplying
+the auth receipt ID in the ``Openstack-Auth-Receipt`` header in a follow-up
+authentication request, with the missing authentication methods, will result in
+a valid token by reusing the successful methods from the first request. This
+allows MFA authentication to be a multi-step process.
+
After you obtain an authentication token, you can:
- Make REST API requests to other OpenStack services. You supply the
@@ -74,6 +84,10 @@ These authentication errors can occur:
| | - The specified ``X-Auth-Token`` header is not valid. |
| | |
| | - The authentication credentials are not valid. |
+| | |
+| | - Not all MFA rules were satisfied. |
+| | |
+| | - The specified ``Openstack-Auth-Receipt`` header is not valid. |
+------------------------+----------------------------------------------------------------------+
| ``Forbidden (403)`` | The identity was successfully authenticated but it is not |
| | authorized to perform the requested action. |
@@ -621,6 +635,168 @@ Example
:language: javascript
+Multi-Step authentication (2-Factor Password and TOTP example)
+==============================================================
+
+.. rest_method:: POST /v3/auth/tokens
+
+Authenticates an identity and generates a token. Uses the password
+authentication method, then the totp method, with an auth receipt in between.
+
+This assumes that MFA has been enabled for the user, and a rule has been
+defined requiring authentication with both password and totp.
+
+The first request body must at least include a payload that specifies one of
+``password`` or ``totp`` authentication methods which includes the credentials
+in addition to an optional scope. If only one method is supplied then an auth
+receipt will be returned. Scope is not retained in the receipt and must be
+resupplied in subsequent requests.
+
+While it is very possible to supply all the required auth methods at once, this
+example shows the multi-step process which is likely to be more common.
+
+More than 2 factors can be used but the same process applies to those as well;
+either all auth methods are supplied at once, or in steps with one or more auth
+receipts in between.
+
+Relationship: ``https://docs.openstack.org/api/openstack-identity/3/rel/auth_tokens``
+
+First Request
+-------------
+
+Parameters
+~~~~~~~~~~
+
+.. rest_parameters:: parameters.yaml
+
+ - nocatalog: nocatalog
+ - name: user_name
+ - auth: auth
+ - user: user
+ - scope: scope_string
+ - password: password
+ - id: user_id
+ - identity: identity
+ - methods: auth_methods_passwd
+
+Example
+~~~~~~~
+
+.. literalinclude:: ./samples/auth/requests/project-id-password.json
+ :language: javascript
+
+Response
+--------
+
+Here we are expecting a 401 status, and a returned auth receipt.
+
+Parameters
+~~~~~~~~~~
+
+.. rest_parameters:: parameters.yaml
+
+ - Openstack-Auth-Receipt: Openstack-Auth-Receipt
+ - methods: auth_methods_receipt
+ - expires_at: receipt_expires_at
+ - issued_at: receipt_issued_at
+ - user: user
+ - required_auth_methods: required_auth_methods
+
+Status Code
+~~~~~~~~~~~
+
+.. rest_status_code:: success status.yaml
+
+ - 401: auth_receipt
+
+.. rest_status_code:: error status.yaml
+
+ - 400
+ - 401: auth_failed
+ - 403
+ - 404
+
+Auth Receipt Example
+~~~~~~~~~~~~~~~~~~~~
+
+.. literalinclude:: ./samples/auth/responses/auth-receipt-password.json
+ :language: javascript
+
+Second Request
+--------------
+
+Parameters
+~~~~~~~~~~
+
+.. rest_parameters:: parameters.yaml
+
+ - Openstack-Auth-Receipt: Openstack-Auth-Receipt
+ - nocatalog: nocatalog
+ - name: user_name
+ - auth: auth
+ - user: user
+ - scope: scope_string
+ - totp: totp
+ - id: user_id
+ - identity: identity
+ - methods: auth_methods_totp
+
+Example
+~~~~~~~
+
+.. literalinclude:: ./samples/auth/requests/project-id-totp.json
+ :language: javascript
+
+Response
+--------
+
+Parameters
+~~~~~~~~~~
+
+.. rest_parameters:: parameters.yaml
+
+ - X-Subject-Token: X-Subject-Token
+ - region_id: region_id_required
+ - methods: auth_methods_passwd
+ - roles: roles
+ - url: endpoint_url
+ - region: endpoint_region
+ - token: token
+ - expires_at: expires_at
+ - system: system_scope_response_body_optional
+ - domain: domain_scope_response_body_optional
+ - project: project_scope_response_body_optional
+ - issued_at: issued_at
+ - catalog: catalog
+ - user: user
+ - audit_ids: audit_ids
+ - interface: endpoint_interface
+ - endpoints: endpoints
+ - type: endpoint_type
+ - id: user_id
+ - name: user_name
+
+Status Codes
+~~~~~~~~~~~~
+
+.. rest_status_code:: success status.yaml
+
+ - 201
+
+.. rest_status_code:: error status.yaml
+
+ - 400
+ - 401: auth_receipt_failure
+ - 403
+ - 404
+
+Project-Scoped Password and TOTP Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. literalinclude:: ./samples/auth/responses/project-scoped-password-totp.json
+ :language: javascript
+
+
Validate and show information for token
=======================================
diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml
index 30b649e1f..e34b425cb 100644
--- a/api-ref/source/v3/parameters.yaml
+++ b/api-ref/source/v3/parameters.yaml
@@ -1,4 +1,12 @@
# variables in header
+Openstack-Auth-Receipt:
+ description: |
+ The auth receipt. A partially successful authentication
+ response returns the auth receipt ID in this header rather than in the
+ response body.
+ in: header
+ required: true
+ type: string
X-Auth-Token:
description: |
A valid authentication token for an
@@ -477,8 +485,8 @@ auth_domain:
type: object
auth_methods:
description: |
- The authentication method, which is ``password``,
- ``token``, or both methods. Indicates the accumulated set of
+ The authentication methods, which are commonly ``password``,
+ ``token``, or other methods. Indicates the accumulated set of
authentication methods that were used to obtain the token. For
example, if the token was obtained by password authentication, it
contains ``password``. Later, if the token is exchanged by using
@@ -506,6 +514,19 @@ auth_methods_passwd:
in: body
required: true
type: array
+auth_methods_receipt:
+ description: |
+ The authentication methods, which are commonly ``password``,
+ ``totp``, or other methods. Indicates the accumulated set of
+ authentication methods that were used to obtain the receipt. For
+ example, if the receipt was obtained by password authentication, it
+ contains ``password``. Later, if the receipt is exchanged by using
+ another authentication method one or more times, the
+ subsequently created receipts could contain both ``password`` and
+ ``totp`` in their ``methods`` attribute.
+ in: body
+ required: true
+ type: array
auth_methods_token:
description: |
The authentication method. For token
@@ -513,6 +534,13 @@ auth_methods_token:
in: body
required: true
type: array
+auth_methods_totp:
+ description: |
+ The authentication method. For totp
+ authentication, specify ``totp``.
+ in: body
+ required: true
+ type: array
auth_token:
description: |
A ``token`` object. The token authentication
@@ -1433,6 +1461,38 @@ projects:
in: body
required: true
type: array
+receipt_expires_at:
+ description: |
+ The date and time when the receipt expires.
+
+ The date and time stamp format is `ISO 8601
+ <https://en.wikipedia.org/wiki/ISO_8601>`_:
+
+ ::
+
+ CCYY-MM-DDThh:mm:ss.sssZ
+
+ For example, ``2015-08-27T09:49:58.000000Z``.
+
+ A ``null`` value indicates that the receipt never expires.
+ in: body
+ required: true
+ type: string
+receipt_issued_at:
+ description: |
+ The date and time when the receipt was issued.
+
+ The date and time stamp format is `ISO 8601
+ <https://en.wikipedia.org/wiki/ISO_8601>`_:
+
+ ::
+
+ CCYY-MM-DDThh:mm:ss.sssZ
+
+ For example, ``2015-08-27T09:49:58.000000Z``.
+ in: body
+ required: true
+ type: string
region_id_not_required:
description: |
(Since v3.2) The ID of the region that contains
@@ -1604,6 +1664,13 @@ request_service_id_registered_limit_body_not_required:
in: body
required: false
type: string
+required_auth_methods:
+ description: |
+ A list of authentication rules that may be used with the auth receipt
+ to complete the authentication process.
+ in: body
+ required: true
+ type: list of lists
resource_limit:
description: |
The override limit.
@@ -1909,6 +1976,12 @@ token:
in: body
required: true
type: object
+totp:
+ description: |
+ The ``totp`` object, contains the authentication information.
+ in: body
+ required: true
+ type: object
user:
description: |
A ``user`` object.
diff --git a/api-ref/source/v3/samples/auth/requests/project-id-totp.json b/api-ref/source/v3/samples/auth/requests/project-id-totp.json
new file mode 100644
index 000000000..fdfcc971e
--- /dev/null
+++ b/api-ref/source/v3/samples/auth/requests/project-id-totp.json
@@ -0,0 +1,20 @@
+{
+ "auth": {
+ "identity": {
+ "methods": [
+ "totp"
+ ],
+ "totp": {
+ "user": {
+ "id": "ee4dfb6e5540447cb3741905149d9b6e",
+ "passcode": "123456"
+ }
+ }
+ },
+ "scope": {
+ "project": {
+ "id": "a6944d763bf64ee6a275f1263fae0352"
+ }
+ }
+ }
+}
diff --git a/api-ref/source/v3/samples/auth/responses/auth-receipt-password.json b/api-ref/source/v3/samples/auth/responses/auth-receipt-password.json
new file mode 100644
index 000000000..40f64f87f
--- /dev/null
+++ b/api-ref/source/v3/samples/auth/responses/auth-receipt-password.json
@@ -0,0 +1,20 @@
+{
+ "receipt":{
+ "expires_at":"2018-07-05T08:39:23.000000Z",
+ "issued_at":"2018-07-05T08:34:23.000000Z",
+ "methods": [
+ "password"
+ ],
+ "user": {
+ "domain": {
+ "id": "default",
+ "name": "Default"
+ },
+ "id": "ee4dfb6e5540447cb3741905149d9b6e",
+ "name": "admin"
+ }
+ },
+ "required_auth_methods": [
+ ["totp", "password"]
+ ]
+}
diff --git a/api-ref/source/v3/samples/auth/responses/project-scoped-password-totp.json b/api-ref/source/v3/samples/auth/responses/project-scoped-password-totp.json
new file mode 100644
index 000000000..6b84e3efe
--- /dev/null
+++ b/api-ref/source/v3/samples/auth/responses/project-scoped-password-totp.json
@@ -0,0 +1,67 @@
+{
+ "token": {
+ "audit_ids": [
+ "3T2dc1CGQxyJsHdDu1xkcw"
+ ],
+ "catalog": [
+ {
+ "endpoints": [
+ {
+ "id": "068d1b359ee84b438266cb736d81de97",
+ "interface": "public",
+ "region": "RegionOne",
+ "region_id": "RegionOne",
+ "url": "http://example.com/identity"
+ },
+ {
+ "id": "8bfc846841ab441ca38471be6d164ced",
+ "interface": "admin",
+ "region": "RegionOne",
+ "region_id": "RegionOne",
+ "url": "http://example.com/identity"
+ },
+ {
+ "id": "beb6d358c3654b4bada04d4663b640b9",
+ "interface": "internal",
+ "region": "RegionOne",
+ "region_id": "RegionOne",
+ "url": "http://example.com/identity"
+ }
+ ],
+ "type": "identity",
+ "id": "050726f278654128aba89757ae25950c",
+ "name": "keystone"
+ }
+ ],
+ "expires_at": "2015-11-07T02:58:43.578887Z",
+ "is_domain": false,
+ "issued_at": "2015-11-07T01:58:43.578929Z",
+ "methods": [
+ "password",
+ "totp"
+ ],
+ "project": {
+ "domain": {
+ "id": "default",
+ "name": "Default"
+ },
+ "id": "a6944d763bf64ee6a275f1263fae0352",
+ "name": "admin"
+ },
+ "roles": [
+ {
+ "id": "51cc68287d524c759f47c811e6463340",
+ "name": "admin"
+ }
+ ],
+ "user": {
+ "domain": {
+ "id": "default",
+ "name": "Default"
+ },
+ "id": "ee4dfb6e5540447cb3741905149d9b6e",
+ "name": "admin",
+ "password_expires_at": "2016-11-06T15:32:17.000000"
+ }
+ }
+}
diff --git a/api-ref/source/v3/status.yaml b/api-ref/source/v3/status.yaml
index 4cecc2ceb..e026069ac 100644
--- a/api-ref/source/v3/status.yaml
+++ b/api-ref/source/v3/status.yaml
@@ -27,6 +27,14 @@
401:
default: |
User must authenticate before making a request.
+ auth_failed: |
+ Authentication attempt has failed.
+ auth_receipt: |
+ User has successfully supplied some auth methods, but not enough for full
+ authentication.
+ auth_receipt_failure: |
+ Authentication attempt has failed. Either the auth receipt has expired, or
+ the additional auth methods supplied were invalid.
403:
default: |
Policy does not allow current user to do this operation.
diff --git a/doc/source/admin/auth-totp.rst b/doc/source/admin/auth-totp.rst
index c3f5d1a8f..3c331be96 100644
--- a/doc/source/admin/auth-totp.rst
+++ b/doc/source/admin/auth-totp.rst
@@ -11,6 +11,8 @@
License for the specific language governing permissions and limitations
under the License.
+.. _auth_totp:
+
===================================
Time-based One-time Password (TOTP)
===================================
diff --git a/doc/source/admin/authentication-mechanisms.rst b/doc/source/admin/authentication-mechanisms.rst
index 83b36a39c..eb15bd4d0 100644
--- a/doc/source/admin/authentication-mechanisms.rst
+++ b/doc/source/admin/authentication-mechanisms.rst
@@ -8,6 +8,7 @@ user and password method.
.. toctree::
:maxdepth: 2
+ multi-factor-authentication
auth-totp
federation/federated_identity
external-authentication
diff --git a/doc/source/admin/multi-factor-authentication.rst b/doc/source/admin/multi-factor-authentication.rst
new file mode 100644
index 000000000..91c85c462
--- /dev/null
+++ b/doc/source/admin/multi-factor-authentication.rst
@@ -0,0 +1,88 @@
+.. _multi_factor_authentication:
+
+===========================
+Multi-Factor Authentication
+===========================
+
+Configuring MFA
+===============
+
+MFA is configured on a per user basis via the user options
+:ref:`multi_factor_auth_rules` and :ref:`multi_factor_auth_enabled`. Until
+these are set the user can authenticate with any one of the enabled auth
+methods.
+
+MFA rules
+---------
+
+The MFA rules allow an admin to force a user to use specific forms of
+authentication or combinations of forms of authentication to get a token.
+
+The rules are specified as follows via the user option
+:ref:`multi_factor_auth_rules`::
+
+ [["password", "totp"], ["password", "custom-auth-method"]]
+
+They are a list of lists. The elements of the sub-lists must be strings and are
+intended to mirror the required authentication method names (e.g. ``password``,
+``totp``, etc) as defined in the ``keystone.conf`` file in the
+``[auth] methods`` option. Each list of methods specifies a rule.
+
+If the auth methods provided by a user match (or exceed) the auth methods in
+the list, that rule is used. The first rule found (rules will not be processed
+in a specific order) that matches will be used. If a user has the ruleset
+defined as ``[["password", "totp"]]`` the user must provide both password and
+totp auth methods (and both methods must succeed) to receive a token. However,
+if a user has a ruleset defined as ``[["password"], ["password", "totp"]]``
+the user may use the ``password`` method on it's own but would be required
+to use both ``password`` and ``totp`` if ``totp`` is specified at all.
+
+Any auth methods that are not defined in ``keystone.conf`` in the
+``[auth] methods`` option are ignored when the rules are processed. Empty
+rules are not allowed. If a rule is empty due to no-valid auth methods
+existing within it, the rule is discarded at authentication time. If there
+are no rules or no valid rules for the user, authentication occurs in the
+default manner: any single configured auth method is sufficient to receive
+a token.
+
+.. note::
+
+ The ``token`` auth method typically should not be specified in any MFA
+ Rules. The ``token`` auth method will include all previous auth methods
+ for the original auth request and will match the appropriate ruleset. This
+ is intentional, as the ``token`` method is used for rescoping/changing
+ active projects.
+
+Enabling MFA
+------------
+
+Before the MFA rules take effect on a user, MFA has to be enabled for that user
+via the user option :ref:`multi_factor_auth_enabled`. By default this is unset,
+and the rules will not take effect until configured.
+
+In the case a user should be exempt from MFA Rules, regardless if they are
+set, the User-Option may be set to ``False``.
+
+Using MFA
+=========
+
+See :ref:`multi_factor_authentication_user_guide` in the user guide for some
+examples.
+
+
+Supported multi-factor authentication methods
+=============================================
+
+TOTP is the only suggested second factor along with password for now, but there
+are plans to include more in future.
+
+TOTP
+----
+
+This is a simple 6 digit passcode generated by both the server and client from
+a known shared secret.
+
+This used in a multi-step fashion is the most common 2-factor method used these
+days.
+
+See: :ref:`auth_totp`
diff --git a/doc/source/admin/resource-options.rst b/doc/source/admin/resource-options.rst
index 23b500868..c79aa1943 100644
--- a/doc/source/admin/resource-options.rst
+++ b/doc/source/admin/resource-options.rst
@@ -22,6 +22,28 @@ User Options
The following options are available on user resources. If left undefined, they
are assumed to be false or disabled.
+These can be set either in the initial user creation (``POST /v3/users``)
+or by updating an existing user to include new options
+(``PATCH /v3/users/{user_id}``):
+
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "ignore_lockout_failure_attempts": true
+ }
+ }
+ }
+
+.. note::
+
+ User options of the ``Boolean`` type can be set to ``True``, ``False``, or
+ ``None``; if the option is set to ``None``, it is removed from the user's
+ data structure.
+
+.. _ignore_change_password_upon_first_use:
+
ignore_change_password_upon_first_use
-------------------------------------
@@ -32,9 +54,21 @@ they log into keystone for the first time. This can be useful for deployments
that auto-generate passwords but want to ensure a user picks a new password
when they start using the deployment.
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "ignore_change_password_upon_first_use": true
+ }
+ }
+ }
+
See the `security compliance documentation
<security-compliance.html>`_ for more details.
+.. _ignore_password_expiry:
+
ignore_password_expiry
----------------------
@@ -45,9 +79,21 @@ Opt into ignoring global password expiration settings defined in
option to ``True`` will allow users to continue using passwords that may be
expired according to global configuration values.
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "ignore_password_expiry": true
+ }
+ }
+ }
+
See the `security compliance documentation
<security-compliance.html>`_ for more details.
+.. _ignore_lockout_failure_attempts:
+
ignore_lockout_failure_attempts
-------------------------------
@@ -56,9 +102,21 @@ Type: ``Boolean``
If ``True``, opt into ignoring the number of times a user has authenticated and
locking out the user as a result.
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "ignore_lockout_failure_attempts": true
+ }
+ }
+ }
+
See the `security compliance documentation
<security-compliance.html>`_ for more details.
+.. _lock_password:
+
lock_password
-------------
@@ -67,9 +125,22 @@ Type: ``Boolean``
If set to ``True``, this option disables the ability for users to change their
password through self-service APIs.
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "lock_password": true
+ }
+ }
+ }
+
+
See the `security compliance documentation
<security-compliance.html>`_ for more details.
+.. _multi_factor_auth_enabled:
+
multi_factor_auth_enabled
-------------------------
@@ -80,6 +151,20 @@ This will result in different behavior at authentication time and the user may
be presented with different authentication requirements based on multi-factor
configuration.
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "multi_factor_auth_enabled": true
+ }
+ }
+ }
+
+See :ref:`multi_factor_authentication` for further details.
+
+.. _multi_factor_auth_rules:
+
multi_factor_auth_rules
-----------------------
@@ -87,3 +172,19 @@ Type: ``List of Lists of Strings``
Define a list of strings that represent the methods required for a user to
authenticate.
+
+.. code-block:: json
+
+ {
+ "user": {
+ "options": {
+ "multi_factor_auth_rules": [
+ ["password", "totp"],
+ ["password", "u2f"]
+ ]
+ }
+ }
+ }
+
+
+See :ref:`multi_factor_authentication` for further details.
diff --git a/doc/source/admin/security-compliance.rst b/doc/source/admin/security-compliance.rst
index 7f9ddb820..5246bb51f 100644
--- a/doc/source/admin/security-compliance.rst
+++ b/doc/source/admin/security-compliance.rst
@@ -42,18 +42,7 @@ indefinitely until the user is explicitly enabled via the API.
You can ensure specific users are never locked out. This can be useful for
service accounts or administrative users. You can do this by setting
-``ignore_lockout_failure_attempts`` to ``true`` via a user update API
-(``PATCH /v3/users/{user_id}``):
-
-.. code-block:: json
-
- {
- "user": {
- "options": {
- "ignore_lockout_failure_attempts": true
- }
- }
- }
+the user option for :ref:`ignore_lockout_failure_attempts`.
Disabling inactive users
------------------------
@@ -85,18 +74,7 @@ authentication (first use), before being able to access any services.
Prior to enabling this feature, you may want to exempt some users that you do
not wish to be required to change their password. You can mark a user as
exempt by setting the user options attribute
-``ignore_change_password_upon_first_use`` to ``true`` via a user update API
-(``PATCH /v3/users/{user_id}``):
-
-.. code-block:: json
-
- {
- "user": {
- "options": {
- "ignore_change_password_upon_first_use": true
- }
- }
- }
+:ref:`ignore_change_password_upon_first_use`.
.. WARNING::
@@ -131,18 +109,7 @@ expiration date, you would need to run a SQL script against the password table
in the database to update the expires_at column.
If there exists a user whose password you do not want to expire, keystone
-supports setting that user's option ``ignore_password_expiry`` to ``true``
-via user update API (``PATCH /v3/users/{user_id}``):
-
-.. code-block:: json
-
- {
- "user": {
- "options": {
- "ignore_password_expiry": true
- }
- }
- }
+supports setting that via the user option :ref:`ignore_password_expiry`.
Configuring password strength requirements
------------------------------------------
@@ -225,24 +192,11 @@ Prevent Self-Service Password Changes
-------------------------------------
If there exists a user who should not be able to change her own password via
-the keystone password change API, keystone supports setting that user's option
-``lock_password`` to ``True`` via the user update API
-(``PATCH /v3/users/{user_id}``):
-
-.. code-block:: json
-
- {
- "user": {
- "options": {
- "lock_password": true
- }
- }
- }
-
-The ``lock_password`` user-option is typically used in the case where passwords
-are managed externally to keystone. The ``lock_password`` option can be set to
-``True``, ``False``, or ``None``; if the option is set to ``None``, it is
-removed from the user's data structure.
+the keystone password change API, keystone supports setting that via the user
+option :ref:`lock_password`.
+
+This is typically used in the case where passwords are managed externally to
+keystone.
.. _Security Hardening PCI-DSS: https://specs.openstack.org/openstack/keystone-specs/specs/keystone/newton/pci-dss.html
diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst
index cc9a17820..a2f320f81 100644
--- a/doc/source/user/index.rst
+++ b/doc/source/user/index.rst
@@ -30,3 +30,4 @@ An end user can find the specific API documentation here, `OpenStack's Identity
trusts.rst
json_home.rst
../api_curl_examples.rst
+ multi-factor-authentication.rst
diff --git a/doc/source/user/multi-factor-authentication.rst b/doc/source/user/multi-factor-authentication.rst
new file mode 100644
index 000000000..48de0cd45
--- /dev/null
+++ b/doc/source/user/multi-factor-authentication.rst
@@ -0,0 +1,130 @@
+.. _multi_factor_authentication_user_guide:
+
+===========================
+Multi-Factor Authentication
+===========================
+
+Configuring MFA
+===============
+
+Configuring MFA right now has to be done entirely by an admin, for how to do
+that, see :ref:`multi_factor_authentication`.
+
+Using MFA
+=========
+
+Multi-Factor Authentication with Keystone can be used in two ways, either you
+treat it like current single method authentication and provide all the details
+upfront, or you doing it as a multi-step process with auth receipts.
+
+Single step
+-----------
+
+In the single step approach you would supply all the required authentication
+methods in your request for a token.
+
+Here is an example using 2 factors (``password`` and ``totp``):
+
+.. code-block:: json
+
+ { "auth": {
+ "identity": {
+ "methods": [
+ "password",
+ "totp"
+ ],
+ "totp": {
+ "user": {
+ "id": "2ed179c6af12496cafa1d279cb51a78f",
+ "passcode": "012345"
+ }
+ },
+ "password": {
+ "user": {
+ "id": "2ed179c6af12496cafa1d279cb51a78f",
+ "password": "super sekret pa55word"
+ }
+ }
+ }
+ }
+ }
+
+If all the supplied auth methods are valid, Keystone will return a token.
+
+Multi-Step
+----------
+
+In the multi-step approach you can supply any one method from the auth rules:
+
+Again we do a 2 factor example, starting with ``password``:
+
+.. code-block:: json
+
+ { "auth": {
+ "identity": {
+ "methods": [
+ "password"
+ ],
+ "password": {
+ "user": {
+ "id": "2ed179c6af12496cafa1d279cb51a78f",
+ "password": "super sekret pa55word"
+ }
+ }
+ }
+ }
+ }
+
+Provided the method is valid, Keystone will still return a ``401``, but will in
+the response header ``Openstack-Auth-Receipt`` return a receipt of valid auth
+method for reuse later.
+
+The response body will also contain information about the auth receipt, and
+what auth methods may be missing:
+
+.. code-block:: json
+
+ {
+ "receipt":{
+ "expires_at":"2018-07-05T08:39:23.000000Z",
+ "issued_at":"2018-07-05T08:34:23.000000Z",
+ "methods": [
+ "password"
+ ],
+ "user": {
+ "domain": {
+ "id": "default",
+ "name": "Default"
+ },
+ "id": "ee4dfb6e5540447cb3741905149d9b6e",
+ "name": "admin"
+ }
+ },
+ "required_auth_methods": [
+ ["totp", "password"]
+ ]
+ }
+
+Now you can continue authenticating by supplying the missing auth methods, and
+supplying the header ``Openstack-Auth-Receipt`` as gotten from the previous
+response:
+
+.. code-block:: json
+
+ { "auth": {
+ "identity": {
+ "methods": [
+ "totp"
+ ],
+ "totp": {
+ "user": {
+ "id": "2ed179c6af12496cafa1d279cb51a78f",
+ "passcode": "012345"
+ }
+ }
+ }
+ }
+ }
+
+Provided the auth methods are valid, Keystone will now supply a token. If not
+you can try again until the auth receipt expires (e.g in case of TOTP timeout).