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.

Files changed (29) hide show
  1. boto3_refresh_session/__init__.py +16 -4
  2. boto3_refresh_session/exceptions.py +115 -3
  3. boto3_refresh_session/methods/__init__.py +14 -0
  4. boto3_refresh_session/methods/custom.py +58 -26
  5. boto3_refresh_session/methods/iot/__init__.py +11 -0
  6. boto3_refresh_session/methods/iot/{core.typed → core.py} +14 -18
  7. boto3_refresh_session/methods/iot/x509.py +614 -0
  8. boto3_refresh_session/methods/sts.py +174 -36
  9. boto3_refresh_session/session.py +48 -32
  10. boto3_refresh_session/utils/__init__.py +18 -0
  11. boto3_refresh_session/utils/cache.py +98 -0
  12. boto3_refresh_session/utils/config/__init__.py +10 -0
  13. boto3_refresh_session/utils/config/config.py +274 -0
  14. boto3_refresh_session/utils/constants.py +41 -0
  15. boto3_refresh_session/utils/internal.py +441 -0
  16. boto3_refresh_session/utils/typing.py +138 -0
  17. {boto3_refresh_session-2.0.5.dist-info → boto3_refresh_session-7.1.3.dist-info}/METADATA +99 -114
  18. boto3_refresh_session-7.1.3.dist-info/RECORD +21 -0
  19. {boto3_refresh_session-2.0.5.dist-info → boto3_refresh_session-7.1.3.dist-info}/WHEEL +1 -1
  20. boto3_refresh_session-7.1.3.dist-info/licenses/LICENSE +373 -0
  21. boto3_refresh_session-7.1.3.dist-info/licenses/NOTICE +21 -0
  22. boto3_refresh_session/methods/ecs.py +0 -109
  23. boto3_refresh_session/methods/iot/__init__.typed +0 -4
  24. boto3_refresh_session/methods/iot/certificate.typed +0 -54
  25. boto3_refresh_session/methods/iot/cognito.typed +0 -16
  26. boto3_refresh_session/utils.py +0 -212
  27. boto3_refresh_session-2.0.5.dist-info/LICENSE +0 -21
  28. boto3_refresh_session-2.0.5.dist-info/NOTICE +0 -12
  29. boto3_refresh_session-2.0.5.dist-info/RECORD +0 -17
@@ -0,0 +1,21 @@
1
+ boto3-refresh-session
2
+ Copyright 2024–2026 Michael Letts
3
+
4
+ boto3-refresh-session (BRS) includes software designed and developed by
5
+ Michael Letts (the author).
6
+
7
+ Although the author was formerly employed by Amazon, this project was
8
+ conceived, designed, developed, and released independently after that
9
+ period of employment.
10
+
11
+ Developers are welcome to use, modify, and adapt this software in
12
+ accordance with the terms of the Mozilla Public License, version 2.0
13
+ (MPL-2.0). Modifications to files covered by the MPL must comply with
14
+ the license’s requirements.
15
+
16
+ If you find boto3-refresh-session (BRS) helpful in your work, a note of
17
+ thanks or a mention in your project’s documentation or acknowledgments
18
+ is appreciated, though not required by the license.
19
+
20
+ This project is licensed under the Mozilla Public License, version 2.0.
21
+ See the LICENSE file for details.
@@ -1,109 +0,0 @@
1
- from __future__ import annotations
2
-
3
- __all__ = ["ECSRefreshableSession"]
4
-
5
- import os
6
-
7
- import requests
8
-
9
- from ..exceptions import BRSError
10
- from ..session import BaseRefreshableSession
11
- from ..utils import TemporaryCredentials
12
-
13
- _ECS_CREDENTIALS_RELATIVE_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
14
- _ECS_CREDENTIALS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
15
- _ECS_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN"
16
- _DEFAULT_ENDPOINT_BASE = "http://169.254.170.2"
17
-
18
-
19
- class ECSRefreshableSession(BaseRefreshableSession, registry_key="ecs"):
20
- """A boto3 session that automatically refreshes temporary AWS credentials
21
- from the ECS container credentials metadata endpoint.
22
-
23
- Parameters
24
- ----------
25
- defer_refresh : bool, optional
26
- If ``True`` then temporary credentials are not automatically
27
- refreshed until they are explicitly needed. If ``False`` then
28
- temporary credentials refresh immediately upon expiration. It
29
- is highly recommended that you use ``True``. Default is ``True``.
30
-
31
- Other Parameters
32
- ----------------
33
- kwargs : dict
34
- Optional keyword arguments passed to :class:`boto3.session.Session`.
35
- """
36
-
37
- def __init__(self, defer_refresh: bool | None = None, **kwargs):
38
- super().__init__(**kwargs)
39
-
40
- self._endpoint = self._resolve_endpoint()
41
- self._headers = self._build_headers()
42
- self._http = self._init_http_session()
43
-
44
- self.initialize(
45
- credentials_method=self._get_credentials,
46
- defer_refresh=defer_refresh is not False,
47
- refresh_method="ecs-container-metadata",
48
- )
49
-
50
- def _resolve_endpoint(self) -> str:
51
- uri = os.environ.get(_ECS_CREDENTIALS_FULL_URI) or os.environ.get(
52
- _ECS_CREDENTIALS_RELATIVE_URI
53
- )
54
- if not uri:
55
- raise BRSError(
56
- "Neither AWS_CONTAINER_CREDENTIALS_FULL_URI nor "
57
- "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI is set. "
58
- "Are you running inside an ECS container?"
59
- )
60
- if uri.startswith("http://") or uri.startswith("https://"):
61
- return uri
62
- return f"{_DEFAULT_ENDPOINT_BASE}{uri}"
63
-
64
- def _build_headers(self) -> dict[str, str]:
65
- token = os.environ.get(_ECS_AUTHORIZATION_TOKEN)
66
- if token:
67
- return {"Authorization": f"Bearer {token}"}
68
- return {}
69
-
70
- def _init_http_session(self) -> requests.Session:
71
- session = requests.Session()
72
- session.headers.update(self._headers)
73
- return session
74
-
75
- def _get_credentials(self) -> TemporaryCredentials:
76
- try:
77
- response = self._http.get(self._endpoint, timeout=3)
78
- response.raise_for_status()
79
- except requests.RequestException as exc:
80
- raise BRSError(
81
- f"Failed to retrieve ECS credentials from {self._endpoint}"
82
- ) from exc
83
-
84
- credentials = response.json()
85
- required = {
86
- "AccessKeyId",
87
- "SecretAccessKey",
88
- "SessionToken",
89
- "Expiration",
90
- }
91
- if not required.issubset(credentials):
92
- raise BRSError(f"Incomplete credentials received: {credentials}")
93
- return {
94
- "access_key": credentials.get("AccessKeyId"),
95
- "secret_key": credentials.get("SecretAccessKey"),
96
- "token": credentials.get("SessionToken"),
97
- "expiry_time": credentials.get("Expiration"), # already ISO8601
98
- }
99
-
100
- def get_identity(self) -> dict[str, str]:
101
- """Returns metadata about ECS.
102
-
103
- Returns
104
- -------
105
- dict[str, str]
106
- Dict containing metadata about ECS.
107
- """
108
-
109
- return {"method": "ecs", "source": "ecs-container-metadata"}
@@ -1,4 +0,0 @@
1
- from .certificate import IoTCertificateRefreshableSession
2
- from .core import IoTRefreshableSession
3
-
4
- __all__ = ["IoTRefreshableSession"]
@@ -1,54 +0,0 @@
1
- __all__ = ["IoTCertificateRefreshableSession"]
2
-
3
- from pathlib import Path
4
- from typing import Any
5
-
6
- from ...exceptions import BRSError
7
- from ...utils import PKCS11, TemporaryCredentials
8
- from .core import BaseIoTRefreshableSession
9
-
10
-
11
- class IoTCertificateRefreshableSession(
12
- BaseIoTRefreshableSession, registry_key="certificate"
13
- ):
14
- def __init__(
15
- self,
16
- endpoint: str,
17
- role_alias: str,
18
- thing_name: str,
19
- certificate: str | bytes,
20
- private_key: str | bytes | None = None,
21
- pkcs11: PKCS11 | None = None,
22
- ca: bytes | None = None,
23
- verify_peer: bool = True,
24
- ):
25
- self.endpoint = endpoint
26
- self.role_alias = role_alias
27
- self.thing_name = thing_name
28
- self.certificate = certificate
29
- self.private_key = private_key
30
- self.pkcs11 = pkcs11
31
- self.ca = ca
32
- self.verify_peer = verify_peer
33
-
34
- if self.certificate and isinstance(self.certificate, str):
35
- with open(Path(self.certificate), "rb") as cert_pem_file:
36
- self.certificate = cert_pem_file.read()
37
-
38
- if self.private_key is None and self.pkcs11 is None:
39
- raise BRSError(
40
- "Either 'private_key' or 'pkcs11' must be provided."
41
- )
42
-
43
- if self.private_key is not None and self.pkcs11 is not None:
44
- raise BRSError(
45
- "Only one of 'private_key' or 'pkcs11' can be provided."
46
- )
47
-
48
- if self.private_key and isinstance(self.private_key, str):
49
- with open(Path(self.private_key), "rb") as private_key_pem_file:
50
- self.private_key = private_key_pem_file.read()
51
-
52
- def _get_credentials(self) -> TemporaryCredentials: ...
53
-
54
- def get_identity(self) -> dict[str, Any]: ...
@@ -1,16 +0,0 @@
1
- __all__ = ["IoTCognitoRefreshableSession"]
2
-
3
- from typing import Any
4
-
5
- from ...utils import TemporaryCredentials
6
- from .core import BaseIoTRefreshableSession
7
-
8
-
9
- class IoTCognitoRefreshableSession(
10
- BaseIoTRefreshableSession, registry_key="cognito"
11
- ):
12
- def __init__(self): ...
13
-
14
- def _get_credentials(self) -> TemporaryCredentials: ...
15
-
16
- def get_identity(self) -> dict[str, Any]: ...
@@ -1,212 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from datetime import datetime
3
- from typing import (
4
- Any,
5
- Callable,
6
- ClassVar,
7
- Generic,
8
- List,
9
- Literal,
10
- TypedDict,
11
- TypeVar,
12
- )
13
-
14
- from boto3.session import Session
15
- from botocore.credentials import (
16
- DeferredRefreshableCredentials,
17
- RefreshableCredentials,
18
- )
19
-
20
- from .exceptions import BRSWarning
21
-
22
- try:
23
- from typing import NotRequired # type: ignore[import]
24
- except ImportError:
25
- from typing_extensions import NotRequired
26
-
27
- #: Type alias for all currently available IoT authentication methods.
28
- IoTAuthenticationMethod = Literal["certificate", "cognito", "__iot_sentinel__"]
29
-
30
- #: Type alias for all currently available credential refresh methods.
31
- Method = Literal[
32
- "sts",
33
- "ecs",
34
- "custom",
35
- "__sentinel__",
36
- ] # TODO: Add iot when implemented
37
-
38
- #: Type alias for all refresh method names.
39
- RefreshMethod = Literal[
40
- "sts-assume-role",
41
- "ecs-container-metadata",
42
- "custom",
43
- ] # Add iot-certificate and iot-cognito when iot implemented
44
-
45
- #: Type alias for all currently registered credential refresh methods.
46
- RegistryKey = TypeVar("RegistryKey", bound=str)
47
-
48
-
49
- class Registry(Generic[RegistryKey]):
50
- """Gives any hierarchy a class-level registry."""
51
-
52
- registry: ClassVar[dict[str, type]] = {}
53
-
54
- def __init_subclass__(cls, *, registry_key: RegistryKey, **kwargs: Any):
55
- super().__init_subclass__(**kwargs)
56
-
57
- if registry_key in cls.registry:
58
- BRSWarning(f"{registry_key!r} already registered. Overwriting.")
59
-
60
- if "sentinel" not in registry_key:
61
- cls.registry[registry_key] = cls
62
-
63
- @classmethod
64
- def items(cls) -> dict[str, type]:
65
- """Typed accessor for introspection / debugging."""
66
-
67
- return dict(cls.registry)
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 RefreshableTemporaryCredentials(TypedDict):
80
- """Refreshable IAM credentials.
81
-
82
- Parameters
83
- ----------
84
- AWS_ACCESS_KEY_ID : str
85
- AWS access key identifier.
86
- AWS_SECRET_ACCESS_KEY : str
87
- AWS secret access key.
88
- AWS_SESSION_TOKEN : str
89
- AWS session token.
90
- """
91
-
92
- AWS_ACCESS_KEY_ID: str
93
- AWS_SECRET_ACCESS_KEY: str
94
- AWS_SESSION_TOKEN: str
95
-
96
-
97
- class CredentialProvider(ABC):
98
- """Defines the abstract surface every refreshable session must expose."""
99
-
100
- @abstractmethod
101
- def _get_credentials(self) -> TemporaryCredentials: ...
102
-
103
- @abstractmethod
104
- def get_identity(self) -> dict[str, Any]: ...
105
-
106
-
107
- class BRSSession(Session):
108
- """Wrapper for boto3.session.Session.
109
-
110
- Other Parameters
111
- ----------------
112
- kwargs : Any
113
- Optional keyword arguments for initializing boto3.session.Session."""
114
-
115
- def __init__(self, **kwargs):
116
- super().__init__(**kwargs)
117
-
118
- def initialize(
119
- self,
120
- credentials_method: Callable,
121
- defer_refresh: bool,
122
- refresh_method: RefreshMethod,
123
- ):
124
- # determining how exactly to refresh expired temporary credentials
125
- if not defer_refresh:
126
- self._credentials = RefreshableCredentials.create_from_metadata(
127
- metadata=credentials_method(),
128
- refresh_using=credentials_method,
129
- method=refresh_method,
130
- )
131
- else:
132
- self._credentials = DeferredRefreshableCredentials(
133
- refresh_using=credentials_method, method=refresh_method
134
- )
135
-
136
- def refreshable_credentials(self) -> RefreshableTemporaryCredentials:
137
- """The current temporary AWS security credentials.
138
-
139
- Returns
140
- -------
141
- RefreshableTemporaryCredentials
142
- Temporary AWS security credentials containing:
143
- AWS_ACCESS_KEY_ID : str
144
- AWS access key identifier.
145
- AWS_SECRET_ACCESS_KEY : str
146
- AWS secret access key.
147
- AWS_SESSION_TOKEN : str
148
- AWS session token.
149
- """
150
-
151
- creds = self.get_credentials().get_frozen_credentials()
152
- return {
153
- "AWS_ACCESS_KEY_ID": creds.access_key,
154
- "AWS_SECRET_ACCESS_KEY": creds.secret_key,
155
- "AWS_SESSION_TOKEN": creds.token,
156
- }
157
-
158
- @property
159
- def credentials(self) -> RefreshableTemporaryCredentials:
160
- """The current temporary AWS security credentials."""
161
-
162
- return self.refreshable_credentials()
163
-
164
-
165
- class Tag(TypedDict):
166
- Key: str
167
- Value: str
168
-
169
-
170
- class PolicyDescriptorType(TypedDict):
171
- arn: str
172
-
173
-
174
- class ProvidedContext(TypedDict):
175
- ProviderArn: str
176
- ContextAssertion: str
177
-
178
-
179
- class AssumeRoleParams(TypedDict):
180
- RoleArn: str
181
- RoleSessionName: str
182
- PolicyArns: NotRequired[List[PolicyDescriptorType]]
183
- Policy: NotRequired[str]
184
- DurationSeconds: NotRequired[int]
185
- ExternalId: NotRequired[str]
186
- SerialNumber: NotRequired[str]
187
- TokenCode: NotRequired[str]
188
- Tags: NotRequired[List[Tag]]
189
- TransitiveTagKeys: NotRequired[List[str]]
190
- SourceIdentity: NotRequired[str]
191
- ProvidedContexts: NotRequired[List[ProvidedContext]]
192
-
193
-
194
- class STSClientParams(TypedDict):
195
- region_name: NotRequired[str]
196
- api_version: NotRequired[str]
197
- use_ssl: NotRequired[bool]
198
- verify: NotRequired[bool | str]
199
- endpoint_url: NotRequired[str]
200
- aws_access_key_id: NotRequired[str]
201
- aws_secret_access_key: NotRequired[str]
202
- aws_session_token: NotRequired[str]
203
- config: NotRequired[Any]
204
- aws_account_id: NotRequired[str]
205
-
206
-
207
- class PKCS11(TypedDict):
208
- pkcs11_loc: str
209
- user_pin: NotRequired[str]
210
- slot_id: NotRequired[int]
211
- token_label: NotRequired[str | None]
212
- private_key_label: NotRequired[str | None]
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Mike Letts
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,12 +0,0 @@
1
- boto3-refresh-session
2
- Copyright 2024 Michael Letts
3
-
4
- boto3-refresh-session (BRS) includes software designed and developed by Michael Letts (the author).
5
-
6
- Although the author was formerly employed by Amazon, this project was conceived, designed, developed, and released independently after that period of employment. It is not affiliated with or endorsed by Amazon Web Services (AWS), Amazon, or any contributors to boto3 or botocore, regardless of their employment status.
7
-
8
- Developers are welcome and encouraged to modify and adapt this software to suit their needs — this is in fact already common practice among some of the largest users of BRS.
9
-
10
- If you find boto3-refresh-session (BRS) helpful in your work, a note of thanks or a mention in your project’s documentation or acknowledgments is appreciated — though not required under the terms of the MIT License.
11
-
12
- Licensed under the MIT License. See the LICENSE file for details.
@@ -1,17 +0,0 @@
1
- boto3_refresh_session/__init__.py,sha256=fhmdy2XmLwM_V__V5qcwByBOFLouPZv6hQIDW17Mfq8,240
2
- boto3_refresh_session/exceptions.py,sha256=cP5d9S8QnUEwXIU3pzMGr6jMOz447kddNJ_UIRERMrk,964
3
- boto3_refresh_session/methods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- boto3_refresh_session/methods/custom.py,sha256=ZJAHgAajz9w6lohDeN-NWrxmZ2LaDxLfGWT2jmoTilQ,3868
5
- boto3_refresh_session/methods/ecs.py,sha256=yAfQbFXMB_RDk-uX_zVVgOt2Lc-1SVx4PJmFyLuDbms,3750
6
- boto3_refresh_session/methods/iot/__init__.typed,sha256=Z33nIB6oCsz9TZwikHfNHgY1SKxkSCdB5rwdPSUl3C4,135
7
- boto3_refresh_session/methods/iot/certificate.typed,sha256=yvKptwH-GagBREI_1AXs_mCaU6vL3AcUDQ58vn7V8QM,1774
8
- boto3_refresh_session/methods/iot/cognito.typed,sha256=0VorzOXHpsVemiGWZzHE9fuX-MZcpqzWQ4nK3gNDUMg,389
9
- boto3_refresh_session/methods/iot/core.typed,sha256=tL-ngB2XYq0XtxhS9mbggCJYdX3eEE0u1Gvcq8sEYGE,1422
10
- boto3_refresh_session/methods/sts.py,sha256=uWvT-ybRVZBusr4jNHyfHOB_AKhs6t0dN_fNI-gkUKM,3268
11
- boto3_refresh_session/session.py,sha256=_Z3uB5Xq3S-dFqOFmWhMQbcd__NPGThjULLPStHI6E4,2914
12
- boto3_refresh_session/utils.py,sha256=ME3sNWZc6oTNUdoRmiNOVmLLp9iSqJe-yfudRV0A46U,5729
13
- boto3_refresh_session-2.0.5.dist-info/LICENSE,sha256=I3ZYTXAjbIly6bm6J-TvFTuuHwTKws4h89QaY5c5HiY,1067
14
- boto3_refresh_session-2.0.5.dist-info/METADATA,sha256=0ZunWqKEinPt-DQD5YZfORW7vXYXqU04mXB7LHpNQDE,8795
15
- boto3_refresh_session-2.0.5.dist-info/NOTICE,sha256=1s8r33qbl1z0YvPB942iWgvbkP94P_e8AnROr1qXXuw,939
16
- boto3_refresh_session-2.0.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
- boto3_refresh_session-2.0.5.dist-info/RECORD,,