boto3-refresh-session 2.0.5__py3-none-any.whl → 7.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of boto3-refresh-session might be problematic. Click here for more details.
- boto3_refresh_session/__init__.py +16 -4
- boto3_refresh_session/exceptions.py +115 -3
- boto3_refresh_session/methods/__init__.py +14 -0
- boto3_refresh_session/methods/custom.py +58 -26
- boto3_refresh_session/methods/iot/__init__.py +11 -0
- boto3_refresh_session/methods/iot/{core.typed → core.py} +14 -18
- boto3_refresh_session/methods/iot/x509.py +614 -0
- boto3_refresh_session/methods/sts.py +174 -36
- boto3_refresh_session/session.py +48 -32
- boto3_refresh_session/utils/__init__.py +18 -0
- boto3_refresh_session/utils/cache.py +98 -0
- boto3_refresh_session/utils/config/__init__.py +10 -0
- boto3_refresh_session/utils/config/config.py +274 -0
- boto3_refresh_session/utils/constants.py +41 -0
- boto3_refresh_session/utils/internal.py +441 -0
- boto3_refresh_session/utils/typing.py +138 -0
- {boto3_refresh_session-2.0.5.dist-info → boto3_refresh_session-7.1.3.dist-info}/METADATA +99 -114
- boto3_refresh_session-7.1.3.dist-info/RECORD +21 -0
- {boto3_refresh_session-2.0.5.dist-info → boto3_refresh_session-7.1.3.dist-info}/WHEEL +1 -1
- boto3_refresh_session-7.1.3.dist-info/licenses/LICENSE +373 -0
- boto3_refresh_session-7.1.3.dist-info/licenses/NOTICE +21 -0
- boto3_refresh_session/methods/ecs.py +0 -109
- boto3_refresh_session/methods/iot/__init__.typed +0 -4
- boto3_refresh_session/methods/iot/certificate.typed +0 -54
- boto3_refresh_session/methods/iot/cognito.typed +0 -16
- boto3_refresh_session/utils.py +0 -212
- boto3_refresh_session-2.0.5.dist-info/LICENSE +0 -21
- boto3_refresh_session-2.0.5.dist-info/NOTICE +0 -12
- boto3_refresh_session-2.0.5.dist-info/RECORD +0 -17
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
|
|
5
|
+
"""This module defines the core building blocks used by `RefreshableSession`
|
|
6
|
+
and method-specific session classes. The intent is to separate registry
|
|
7
|
+
mechanics, credential refresh contracts, and boto3 session behavior so each
|
|
8
|
+
concern is clear and testable.
|
|
9
|
+
|
|
10
|
+
`Registry` is a lightweight class-level registry. Subclasses register
|
|
11
|
+
themselves by key at import time, enabling factory-style lookup without
|
|
12
|
+
hard-coded class references. This is how `RefreshableSession` discovers method
|
|
13
|
+
implementations.
|
|
14
|
+
|
|
15
|
+
`refreshable_session` is a decorator that wraps `__init__` and guarantees a
|
|
16
|
+
`__post_init__` hook runs after `boto3.Session` initialization. This allows
|
|
17
|
+
`BRSSession` to create refreshable credentials only after the boto3 Session is
|
|
18
|
+
set up, avoiding circular and ordering issues. It also prevents double
|
|
19
|
+
wrapping on repeated decoration.
|
|
20
|
+
|
|
21
|
+
`CredentialProvider` is a small abstract class that defines the contract for
|
|
22
|
+
refreshable sessions: implement `_get_credentials` (returns temporary creds)
|
|
23
|
+
and `get_identity` (describes the caller identity). The concrete refresh
|
|
24
|
+
methods (STS, IoT, custom) only need to satisfy this interface.
|
|
25
|
+
|
|
26
|
+
`BRSSession` is the concrete wrapper over `boto3.Session`. It owns refreshable
|
|
27
|
+
credential construction, wiring the botocore session to those credentials, and
|
|
28
|
+
client caching with normalized cache keys. It acts as the base implementation
|
|
29
|
+
for session mechanics.
|
|
30
|
+
|
|
31
|
+
`BaseRefreshableSession` and `BaseIoTRefreshableSession` combine `Registry`,
|
|
32
|
+
`CredentialProvider`, and `BRSSession` to create abstract roots for method
|
|
33
|
+
families. They do not implement credential retrieval themselves, but provide a
|
|
34
|
+
common surface and registration behavior for subclasses like STS or IoT X.509.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"AWSCRTResponse",
|
|
39
|
+
"BRSSession",
|
|
40
|
+
"BaseIoTRefreshableSession",
|
|
41
|
+
"BaseRefreshableSession",
|
|
42
|
+
"CredentialProvider",
|
|
43
|
+
"Registry",
|
|
44
|
+
"refreshable_session",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
from abc import ABC, abstractmethod
|
|
48
|
+
from functools import wraps
|
|
49
|
+
from typing import Any, Callable, ClassVar, Generic, TypeVar, cast
|
|
50
|
+
|
|
51
|
+
from awscrt.http import HttpHeaders
|
|
52
|
+
from boto3.session import Session
|
|
53
|
+
from botocore.client import BaseClient
|
|
54
|
+
from botocore.config import Config
|
|
55
|
+
from botocore.credentials import (
|
|
56
|
+
DeferredRefreshableCredentials,
|
|
57
|
+
RefreshableCredentials,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
from ..exceptions import BRSCacheError, BRSWarning
|
|
61
|
+
from .cache import ClientCache
|
|
62
|
+
from .typing import (
|
|
63
|
+
Identity,
|
|
64
|
+
IoTAuthenticationMethod,
|
|
65
|
+
Method,
|
|
66
|
+
RefreshMethod,
|
|
67
|
+
RegistryKey,
|
|
68
|
+
TemporaryCredentials,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _freeze_value(value: Any) -> Any:
|
|
73
|
+
"""Recursively freezes a value for use in cache keys.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
value : Any
|
|
78
|
+
The value to freeze.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
if isinstance(value, dict):
|
|
82
|
+
return tuple(
|
|
83
|
+
sorted((key, _freeze_value(val)) for key, val in value.items())
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# checking for list, tuple, or set just to be safe
|
|
87
|
+
if isinstance(value, (list, tuple, set)):
|
|
88
|
+
return tuple(sorted(_freeze_value(item) for item in value))
|
|
89
|
+
return value
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _config_cache_key(config: Config | None) -> Any:
|
|
93
|
+
"""Generates a cache key for a botocore.config.Config object.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
config : Config | None
|
|
98
|
+
The Config object to generate a cache key for.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
if config is None:
|
|
102
|
+
return None
|
|
103
|
+
|
|
104
|
+
# checking for user-provided options first
|
|
105
|
+
options = getattr(config, "_user_provided_options", None)
|
|
106
|
+
if options is None:
|
|
107
|
+
# __dict__ is pedantic but stable
|
|
108
|
+
return _freeze_value(getattr(config, "__dict__", {}))
|
|
109
|
+
return _freeze_value(options)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class CredentialProvider(ABC):
|
|
113
|
+
"""Defines the abstract surface every refreshable session must expose."""
|
|
114
|
+
|
|
115
|
+
@abstractmethod
|
|
116
|
+
def _get_credentials(self) -> TemporaryCredentials: ...
|
|
117
|
+
|
|
118
|
+
@abstractmethod
|
|
119
|
+
def get_identity(self) -> Identity: ...
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class Registry(Generic[RegistryKey]):
|
|
123
|
+
"""Gives any hierarchy a class-level registry."""
|
|
124
|
+
|
|
125
|
+
registry: ClassVar[dict[str, type]] = {}
|
|
126
|
+
|
|
127
|
+
def __init_subclass__(cls, *, registry_key: RegistryKey, **kwargs: Any):
|
|
128
|
+
super().__init_subclass__(**kwargs)
|
|
129
|
+
|
|
130
|
+
if registry_key in cls.registry:
|
|
131
|
+
BRSWarning.warn(
|
|
132
|
+
f"{registry_key!r} already registered. Overwriting."
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if "sentinel" not in registry_key:
|
|
136
|
+
cls.registry[registry_key] = cls
|
|
137
|
+
|
|
138
|
+
@classmethod
|
|
139
|
+
def items(cls) -> dict[str, type]:
|
|
140
|
+
"""Typed accessor for introspection / debugging."""
|
|
141
|
+
|
|
142
|
+
return dict(cls.registry)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# defining this here instead of utils to avoid circular imports lol
|
|
146
|
+
T_BRSSession = TypeVar("T_BRSSession", bound="BRSSession")
|
|
147
|
+
|
|
148
|
+
#: Type alias for a generic refreshable session type.
|
|
149
|
+
BRSSessionType = type[T_BRSSession]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def refreshable_session(
|
|
153
|
+
cls: BRSSessionType,
|
|
154
|
+
) -> BRSSessionType:
|
|
155
|
+
"""Wraps cls.__init__ so self.__post_init__ runs after init (if present).
|
|
156
|
+
|
|
157
|
+
In plain English: this is essentially a post-initialization hook.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
BRSSessionType
|
|
162
|
+
The decorated class.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
init = getattr(cls, "__init__", None)
|
|
166
|
+
|
|
167
|
+
# synthesize __init__ if undefined in the class
|
|
168
|
+
if init in (None, object.__init__):
|
|
169
|
+
|
|
170
|
+
def __init__(self, *args, **kwargs):
|
|
171
|
+
super(cls, self).__init__(*args, **kwargs)
|
|
172
|
+
post = getattr(self, "__post_init__", None)
|
|
173
|
+
if callable(post) and not getattr(self, "_post_inited", False):
|
|
174
|
+
post()
|
|
175
|
+
setattr(self, "_post_inited", True)
|
|
176
|
+
|
|
177
|
+
cls.__init__ = __init__ # type: ignore[assignment]
|
|
178
|
+
return cls
|
|
179
|
+
|
|
180
|
+
# avoids double wrapping
|
|
181
|
+
if getattr(init, "__post_init_wrapped__", False):
|
|
182
|
+
return cls
|
|
183
|
+
|
|
184
|
+
@wraps(init)
|
|
185
|
+
def wrapper(self, *args, **kwargs):
|
|
186
|
+
init(self, *args, **kwargs)
|
|
187
|
+
post = getattr(self, "__post_init__", None)
|
|
188
|
+
if callable(post) and not getattr(self, "_post_inited", False):
|
|
189
|
+
post()
|
|
190
|
+
setattr(self, "_post_inited", True)
|
|
191
|
+
|
|
192
|
+
wrapper.__post_init_wrapped__ = True # type: ignore[attr-defined]
|
|
193
|
+
cls.__init__ = cast(Callable[..., None], wrapper)
|
|
194
|
+
return cls
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class BRSSession(Session):
|
|
198
|
+
"""Wrapper for boto3.session.Session.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
refresh_method : RefreshMethod
|
|
203
|
+
The method to use for refreshing temporary credentials.
|
|
204
|
+
defer_refresh : bool, optional
|
|
205
|
+
If ``True`` then temporary credentials are not automatically refreshed
|
|
206
|
+
until they are explicitly needed. If ``False`` then temporary
|
|
207
|
+
credentials refresh immediately upon expiration. It is highly
|
|
208
|
+
recommended that you use ``True``. Default is ``True``.
|
|
209
|
+
advisory_timeout : int, optional
|
|
210
|
+
USE THIS ARGUMENT WITH CAUTION!!!
|
|
211
|
+
|
|
212
|
+
Botocore will attempt to refresh credentials early according to
|
|
213
|
+
this value (in seconds), but will continue using the existing
|
|
214
|
+
credentials if refresh fails. Default is 15 minutes (900 seconds).
|
|
215
|
+
mandatory_timeout : int, optional
|
|
216
|
+
USE THIS ARGUMENT WITH CAUTION!!!
|
|
217
|
+
|
|
218
|
+
Botocore requires a successful refresh before continuing. If
|
|
219
|
+
refresh fails in this window (in seconds), API calls may fail.
|
|
220
|
+
Default is 10 minutes (600 seconds).
|
|
221
|
+
cache_clients : bool, optional
|
|
222
|
+
If ``True`` then clients created by this session will be cached and
|
|
223
|
+
reused for subsequent calls to :meth:`client()` with the same
|
|
224
|
+
parameter signatures. Due to the memory overhead of clients, the
|
|
225
|
+
default is ``True`` in order to protect system resources.
|
|
226
|
+
|
|
227
|
+
Other Parameters
|
|
228
|
+
----------------
|
|
229
|
+
kwargs : Any
|
|
230
|
+
Optional keyword arguments for initializing boto3.session.Session.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
def __init__(
|
|
234
|
+
self,
|
|
235
|
+
refresh_method: RefreshMethod,
|
|
236
|
+
defer_refresh: bool | None = None,
|
|
237
|
+
advisory_timeout: int | None = None,
|
|
238
|
+
mandatory_timeout: int | None = None,
|
|
239
|
+
cache_clients: bool | None = None,
|
|
240
|
+
**kwargs,
|
|
241
|
+
):
|
|
242
|
+
# initializing parameters
|
|
243
|
+
self.refresh_method: RefreshMethod = refresh_method
|
|
244
|
+
self.defer_refresh: bool = defer_refresh is not False
|
|
245
|
+
self.advisory_timeout: int | None = advisory_timeout
|
|
246
|
+
self.mandatory_timeout: int | None = mandatory_timeout
|
|
247
|
+
self.cache_clients: bool | None = cache_clients is not False
|
|
248
|
+
|
|
249
|
+
# initializing Session
|
|
250
|
+
super().__init__(**kwargs)
|
|
251
|
+
|
|
252
|
+
# initializing client cache
|
|
253
|
+
self._client_cache: ClientCache = ClientCache()
|
|
254
|
+
|
|
255
|
+
def __post_init__(self):
|
|
256
|
+
if not self.defer_refresh:
|
|
257
|
+
self._credentials = RefreshableCredentials.create_from_metadata(
|
|
258
|
+
metadata=self._get_credentials(),
|
|
259
|
+
refresh_using=self._get_credentials,
|
|
260
|
+
method=self.refresh_method,
|
|
261
|
+
advisory_timeout=self.advisory_timeout,
|
|
262
|
+
mandatory_timeout=self.mandatory_timeout,
|
|
263
|
+
)
|
|
264
|
+
else:
|
|
265
|
+
self._credentials = DeferredRefreshableCredentials(
|
|
266
|
+
refresh_using=self._get_credentials, method=self.refresh_method
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# without this, boto3 won't use the refreshed credentials properly in
|
|
270
|
+
# clients and resources, depending on how they were created
|
|
271
|
+
self._session._credentials = self._credentials
|
|
272
|
+
|
|
273
|
+
def client(self, *args, **kwargs) -> BaseClient:
|
|
274
|
+
"""Creates a low-level service client by name.
|
|
275
|
+
|
|
276
|
+
Parameters
|
|
277
|
+
----------
|
|
278
|
+
*args : Any
|
|
279
|
+
Positional arguments for :meth:`boto3.session.Session.client`.
|
|
280
|
+
**kwargs : Any
|
|
281
|
+
Keyword arguments for :meth:`boto3.session.Session.client`.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
BaseClient
|
|
286
|
+
A low-level service client.
|
|
287
|
+
|
|
288
|
+
Notes
|
|
289
|
+
-----
|
|
290
|
+
This method overrides the default
|
|
291
|
+
:meth:`boto3.session.Session.client` method. If client caching is
|
|
292
|
+
enabled, it will return a cached client instance for the given
|
|
293
|
+
service and parameters. Else, it will create and return a new client
|
|
294
|
+
instance.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
# check if caching is enabled
|
|
298
|
+
if self.cache_clients:
|
|
299
|
+
# checking if Config was passed as a positional arg
|
|
300
|
+
_args = [
|
|
301
|
+
_config_cache_key(arg) if isinstance(arg, Config) else arg
|
|
302
|
+
for arg in args
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
# popping trailing None values from args, preserving None in middle
|
|
306
|
+
while _args and _args[-1] is None:
|
|
307
|
+
_args.pop()
|
|
308
|
+
_args = tuple(_args)
|
|
309
|
+
|
|
310
|
+
# checking if Config was passed as a keyword arg
|
|
311
|
+
_kwargs = kwargs.copy()
|
|
312
|
+
if _kwargs.get("config") is not None:
|
|
313
|
+
_kwargs["config"] = _config_cache_key(_kwargs["config"])
|
|
314
|
+
|
|
315
|
+
# preemptively removing None values from kwargs
|
|
316
|
+
_kwargs = {
|
|
317
|
+
key: value
|
|
318
|
+
for key, value in _kwargs.items()
|
|
319
|
+
if value is not None
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
# creating a unique key for the client cache
|
|
323
|
+
key = (_args, tuple(sorted(_kwargs.items())))
|
|
324
|
+
|
|
325
|
+
# if client exists in cache, return it
|
|
326
|
+
if (_cached_client := self._client_cache.get(key)) is not None:
|
|
327
|
+
return _cached_client
|
|
328
|
+
|
|
329
|
+
# else -- initialize, cache, and return it
|
|
330
|
+
client = super().client(*args, **kwargs)
|
|
331
|
+
|
|
332
|
+
# attempting to cache and return the client
|
|
333
|
+
try:
|
|
334
|
+
self._client_cache[key] = client
|
|
335
|
+
return client
|
|
336
|
+
|
|
337
|
+
# if caching fails, return cached client if possible
|
|
338
|
+
except BRSCacheError:
|
|
339
|
+
return (
|
|
340
|
+
cached
|
|
341
|
+
if (cached := self._client_cache.get(key)) is not None
|
|
342
|
+
else client
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# return a new client if caching is disabled
|
|
346
|
+
else:
|
|
347
|
+
return super().client(*args, **kwargs)
|
|
348
|
+
|
|
349
|
+
def refreshable_credentials(self) -> TemporaryCredentials:
|
|
350
|
+
"""The current temporary AWS security credentials.
|
|
351
|
+
|
|
352
|
+
Returns
|
|
353
|
+
-------
|
|
354
|
+
TemporaryCredentials
|
|
355
|
+
Temporary AWS security credentials containing:
|
|
356
|
+
access_key : str
|
|
357
|
+
AWS access key identifier.
|
|
358
|
+
secret_key : str
|
|
359
|
+
AWS secret access key.
|
|
360
|
+
token : str
|
|
361
|
+
AWS session token.
|
|
362
|
+
expiry_time : str
|
|
363
|
+
Expiration timestamp in ISO 8601 format.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
creds = (
|
|
367
|
+
self._credentials
|
|
368
|
+
if self._credentials is not None
|
|
369
|
+
else self.get_credentials()
|
|
370
|
+
)
|
|
371
|
+
frozen_creds = creds.get_frozen_credentials()
|
|
372
|
+
return {
|
|
373
|
+
"access_key": frozen_creds.access_key,
|
|
374
|
+
"secret_key": frozen_creds.secret_key,
|
|
375
|
+
"token": frozen_creds.token,
|
|
376
|
+
"expiry_time": creds._expiry_time.isoformat(),
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def credentials(self) -> TemporaryCredentials:
|
|
381
|
+
"""The current temporary AWS security credentials."""
|
|
382
|
+
|
|
383
|
+
return self.refreshable_credentials()
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class BaseRefreshableSession(
|
|
387
|
+
Registry[Method],
|
|
388
|
+
CredentialProvider,
|
|
389
|
+
BRSSession,
|
|
390
|
+
registry_key="__sentinel__",
|
|
391
|
+
):
|
|
392
|
+
"""Abstract base class for implementing refreshable AWS sessions.
|
|
393
|
+
|
|
394
|
+
Provides a common interface and factory registration mechanism
|
|
395
|
+
for subclasses that generate temporary credentials using various
|
|
396
|
+
AWS authentication methods (e.g., STS).
|
|
397
|
+
|
|
398
|
+
Subclasses must implement ``_get_credentials()`` and ``get_identity()``.
|
|
399
|
+
They should also register themselves using the ``method=...`` argument
|
|
400
|
+
to ``__init_subclass__``.
|
|
401
|
+
|
|
402
|
+
Parameters
|
|
403
|
+
----------
|
|
404
|
+
registry : dict[str, type[BaseRefreshableSession]]
|
|
405
|
+
Class-level registry mapping method names to registered session types.
|
|
406
|
+
"""
|
|
407
|
+
|
|
408
|
+
def __init__(self, **kwargs):
|
|
409
|
+
super().__init__(**kwargs)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class BaseIoTRefreshableSession(
|
|
413
|
+
Registry[IoTAuthenticationMethod],
|
|
414
|
+
CredentialProvider,
|
|
415
|
+
BRSSession,
|
|
416
|
+
registry_key="__iot_sentinel__",
|
|
417
|
+
):
|
|
418
|
+
def __init__(self, **kwargs):
|
|
419
|
+
super().__init__(**kwargs)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class AWSCRTResponse:
|
|
423
|
+
"""Lightweight response collector for awscrt HTTP."""
|
|
424
|
+
|
|
425
|
+
def __init__(self):
|
|
426
|
+
"""Initialize to default for when callbacks are called."""
|
|
427
|
+
|
|
428
|
+
self.status_code = None
|
|
429
|
+
self.headers = None
|
|
430
|
+
self.body = bytearray()
|
|
431
|
+
|
|
432
|
+
def on_response(self, http_stream, status_code, headers, **kwargs):
|
|
433
|
+
"""Process awscrt.io response."""
|
|
434
|
+
|
|
435
|
+
self.status_code = status_code
|
|
436
|
+
self.headers = HttpHeaders(headers)
|
|
437
|
+
|
|
438
|
+
def on_body(self, http_stream, chunk, **kwargs):
|
|
439
|
+
"""Process awscrt.io body."""
|
|
440
|
+
|
|
441
|
+
self.body.extend(chunk)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
|
|
5
|
+
"""Shared type definitions used across refreshable session modules."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"AssumeRoleParams",
|
|
11
|
+
"CustomCredentialsMethod",
|
|
12
|
+
"CustomCredentialsMethodArgs",
|
|
13
|
+
"Identity",
|
|
14
|
+
"IoTAuthenticationMethod",
|
|
15
|
+
"Method",
|
|
16
|
+
"PKCS11",
|
|
17
|
+
"RefreshMethod",
|
|
18
|
+
"RegistryKey",
|
|
19
|
+
"STSClientParams",
|
|
20
|
+
"TemporaryCredentials",
|
|
21
|
+
"Transport",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
from datetime import datetime
|
|
25
|
+
from typing import (
|
|
26
|
+
Any,
|
|
27
|
+
List,
|
|
28
|
+
Literal,
|
|
29
|
+
Mapping,
|
|
30
|
+
Protocol,
|
|
31
|
+
TypeAlias,
|
|
32
|
+
TypedDict,
|
|
33
|
+
TypeVar,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from typing import NotRequired # type: ignore[import]
|
|
38
|
+
except ImportError:
|
|
39
|
+
from typing_extensions import NotRequired
|
|
40
|
+
|
|
41
|
+
#: Type alias for all currently available IoT authentication methods.
|
|
42
|
+
IoTAuthenticationMethod = Literal["x509", "__iot_sentinel__"]
|
|
43
|
+
|
|
44
|
+
#: Type alias for all currently available credential refresh methods.
|
|
45
|
+
Method = Literal[
|
|
46
|
+
"custom",
|
|
47
|
+
"iot",
|
|
48
|
+
"sts",
|
|
49
|
+
"__sentinel__",
|
|
50
|
+
"__iot_sentinel__",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
#: Type alias for all refresh method names.
|
|
54
|
+
RefreshMethod = Literal[
|
|
55
|
+
"custom",
|
|
56
|
+
"iot-x509",
|
|
57
|
+
"sts-assume-role",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
#: Type alias for all currently registered credential refresh methods.
|
|
61
|
+
RegistryKey = TypeVar("RegistryKey", bound=str)
|
|
62
|
+
|
|
63
|
+
#: Type alias for values returned by get_identity
|
|
64
|
+
Identity: TypeAlias = dict[str, Any]
|
|
65
|
+
|
|
66
|
+
#: Type alias for acceptable transports
|
|
67
|
+
Transport: TypeAlias = Literal["x509", "ws"]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TemporaryCredentials(TypedDict):
|
|
71
|
+
"""Temporary IAM credentials."""
|
|
72
|
+
|
|
73
|
+
access_key: str
|
|
74
|
+
secret_key: str
|
|
75
|
+
token: str
|
|
76
|
+
expiry_time: datetime | str
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class _CustomCredentialsMethod(Protocol):
|
|
80
|
+
def __call__(self, **kwargs: Any) -> TemporaryCredentials: ...
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
#: Type alias for custom credential retrieval methods.
|
|
84
|
+
CustomCredentialsMethod: TypeAlias = _CustomCredentialsMethod
|
|
85
|
+
|
|
86
|
+
#: Type alias for custom credential method arguments.
|
|
87
|
+
CustomCredentialsMethodArgs: TypeAlias = Mapping[str, Any]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class Tag(TypedDict):
|
|
91
|
+
Key: str
|
|
92
|
+
Value: str
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class PolicyDescriptorType(TypedDict):
|
|
96
|
+
arn: str
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ProvidedContext(TypedDict):
|
|
100
|
+
ProviderArn: str
|
|
101
|
+
ContextAssertion: str
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class AssumeRoleParams(TypedDict):
|
|
105
|
+
RoleArn: str
|
|
106
|
+
RoleSessionName: str
|
|
107
|
+
PolicyArns: NotRequired[List[PolicyDescriptorType]]
|
|
108
|
+
Policy: NotRequired[str]
|
|
109
|
+
DurationSeconds: NotRequired[int]
|
|
110
|
+
ExternalId: NotRequired[str]
|
|
111
|
+
SerialNumber: NotRequired[str]
|
|
112
|
+
TokenCode: NotRequired[str]
|
|
113
|
+
Tags: NotRequired[List[Tag]]
|
|
114
|
+
TransitiveTagKeys: NotRequired[List[str]]
|
|
115
|
+
SourceIdentity: NotRequired[str]
|
|
116
|
+
ProvidedContexts: NotRequired[List[ProvidedContext]]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class STSClientParams(TypedDict):
|
|
120
|
+
service_name: NotRequired[str]
|
|
121
|
+
region_name: NotRequired[str]
|
|
122
|
+
api_version: NotRequired[str]
|
|
123
|
+
use_ssl: NotRequired[bool]
|
|
124
|
+
verify: NotRequired[bool | str]
|
|
125
|
+
endpoint_url: NotRequired[str]
|
|
126
|
+
aws_access_key_id: NotRequired[str]
|
|
127
|
+
aws_secret_access_key: NotRequired[str]
|
|
128
|
+
aws_session_token: NotRequired[str]
|
|
129
|
+
config: NotRequired[Any]
|
|
130
|
+
aws_account_id: NotRequired[str]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class PKCS11(TypedDict):
|
|
134
|
+
pkcs11_lib: str
|
|
135
|
+
user_pin: NotRequired[str]
|
|
136
|
+
slot_id: NotRequired[int]
|
|
137
|
+
token_label: NotRequired[str | None]
|
|
138
|
+
private_key_label: NotRequired[str | None]
|