1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
.. _gares:
Globus Auth Requirements Errors (GAREs)
=======================================
'Globus Auth Requirements Error' is a response format that conveys to a client any
modifications to a session (i.e., "boosting") that will be required
to complete a particular request.
The ``globus_sdk.gare`` module provides a number of tools to make it easier to
identify and handle these errors when they occur.
GARE
----
The ``GARE`` class provides a model for working with Globus Auth Requirements Error
responses.
Services in the Globus ecosystem may need to communicate authorization requirements
to their consumers. For example, a service may need to instruct clients to have the user
consent to an additional scope, ``"foo"``. In such a case, ``GARE`` can provide
serialization into the well-known Globus Auth Requirements Error format:
.. code-block:: python
from globus_sdk.gare import GARE
error_doc = GARE(
code="ConsentRequired",
authorization_parameters=GlobusAuthorizationParameters(
required_scopes=["foo"],
session_message="Missing required 'foo' consent",
),
)
# Render a strict dictionary
error.to_dict()
If non-canonical fields are needed, the ``extra`` argument can be used to
supply a dictionary of additional fields to include. Non-canonical fields present
in the provided dictionary when calling ``from_dict()`` are stored similarly.
You can include these fields in the rendered output dictionary
by specifying ``include_extra=True`` when calling ``to_dict()``.
.. code-block:: python
from globus_sdk.gare import GARE
error = GARE(
code="ConsentRequired",
authorization_parameters=GlobusAuthorizationParameters(
required_scopes=["foo"],
session_message="Missing required 'foo' consent",
),
extra={
"message": "Missing required 'foo' consent",
"request_id": "WmMV97A1w",
"required_scopes": ["foo"],
"resource": "/transfer",
},
)
# Render a dictionary with extra fields
error.to_dict(include_extra=True)
These fields are stored by both the ``GARE`` and ``GlobusAuthenticationParameters``
classes in an ``extra`` attribute.
.. note::
Non-canonical fields in a Globus Auth Requirements Error are primarily intended
to make it easier for services to provide backward-compatibile error responses
to clients that have not adopted the Globus Auth Requirements Error format. Avoid
using non-canonical fields for any data that should be generically understood by
a consumer of the error response.
.. _globus_app_gare_integration:
GlobusApp Integration
---------------------
In order to standardize a common GARE-handling approach, the SDK's
:ref:`GlobusApp <globus_apps>` contains a built-in GARE redrive mechanism (disabled
by default).
When enabled (setting the config flag ``auto_redrive_gares`` to ``True``), any
client created with a GlobusApp will receive an additional request-transport retry
handler. This handler will intercept the first occurrence of a 403 response which
parses as a GARE and "redrive it", by:
1. Initiating a fresh login request with the defined ``LoginFlowManager``
2. Caching new tokens for subsequent requests
3. Re-attempting the original request with the new tokens
This allows for very simple error-handling, particularly in scripts, wherein the
executing user or client is automatically prompted to remediate manually-required
steps (e.g., consent, MFA) without any additional code.
.. code-block:: python
from globus_sdk import UserApp, GlobusAppConfig, TransferClient
config = GlobusAppConfig(auto_redrive_gares=True)
with UserApp("my-gare-demo", "<client-id>", config=config) as app:
tc = TransferClient(app=app)
# If the transfer service were to return a 403 GARE, the script runner would be
# prompted to log in with any explicit specifications, e.g., MFA, consents.
# Once they complete the login flow (by providing the newly minted auth code),
# the original request is attempted once more.
task = tc.submit_transfer(your_transfer_data)
Parsing Responses
-----------------
If you are writing a client to a Globus API, the ``gare`` subpackage provides utilities
to detect legacy Globus Auth requirements error response formats and normalize them.
To detect if a ``GlobusAPIError``, ``ErrorSubdocument``, or JSON response
dictionary represents an error that can be converted to a Globus Auth
Requirements Error, you can use, e.g.,:
.. code-block:: python
from globus_sdk import gare
error_dict = {
"code": "ConsentRequired",
"message": "Missing required foo consent",
}
# The dict is not a Globus Auth Requirements Error, so `False` is returned.
gare.is_auth_requirements_error(error_dict)
# The dict is not a Globus Auth Requirements Error and cannot be converted.
gare.to_auth_requirements_error(error_dict) # None
error_dict = {
"code": "ConsentRequired",
"message": "Missing required foo consent",
"required_scopes": ["urn:globus:auth:scope:transfer.api.globus.org:all[*foo]"],
}
gare.is_auth_requirements_error(error_dict) # True
gare.to_auth_requirements_error(error_dict) # GARE
.. note::
If a ``GlobusAPIError`` represents multiple errors that were returned in an
array, ``to_auth_requirements_error()`` only returns the first error in that
array that can be converted to the Globus Auth Requirements Error response format.
In this case (and in general) it's preferable to use
``to_auth_requirements_errors()`` (which also accepts a list of
``GlobusAPIError``\ s, ``ErrorSubdocument``\ s, and JSON response dictionaries):
.. code-block:: python
gare.to_auth_requirements_error(other_error) # GARE
gare.to_auth_requirements_errors([other_error]) # [GARE, ...]
Notes
-----
``GARE`` enforces types strictly when parsing a Globus Auth Requirements Error
response dictionary, and will raise a :class:`globus_sdk.ValidationError` if a
supported field is supplied with a value of the wrong type.
``GARE`` does not attempt to mimic or itself enforce any logic specific to the
Globus Auth service with regard to what represents a valid combination of fields
(e.g., ``session_required_mfa`` requires either ``session_required_identities`` or
``session_required_single_domain`` in order to be properly handled).
Reference
---------
.. currentmodule:: globus_sdk.gare
.. autoclass:: GARE
:members:
:inherited-members:
.. autoclass:: GlobusAuthorizationParameters
:members:
:inherited-members:
.. autofunction:: to_gare
.. autofunction:: to_gares
.. autofunction:: is_gare
.. autofunction:: has_gares
|