esd-services-api-client 0.9.1__py3-none-any.whl → 0.9.2__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.
- esd_services_api_client/_version.py +1 -1
- esd_services_api_client/boxer/README.md +21 -0
- esd_services_api_client/boxer/_auth.py +72 -7
- esd_services_api_client/boxer/_connector.py +7 -3
- {esd_services_api_client-0.9.1.dist-info → esd_services_api_client-0.9.2.dist-info}/METADATA +1 -1
- {esd_services_api_client-0.9.1.dist-info → esd_services_api_client-0.9.2.dist-info}/RECORD +8 -8
- {esd_services_api_client-0.9.1.dist-info → esd_services_api_client-0.9.2.dist-info}/LICENSE +0 -0
- {esd_services_api_client-0.9.1.dist-info → esd_services_api_client-0.9.2.dist-info}/WHEEL +0 -0
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.9.
|
1
|
+
__version__ = '0.9.2'
|
@@ -68,3 +68,24 @@ from esd_services_api_client.boxer import BoxerConnector
|
|
68
68
|
conn = BoxerConnector(base_url="https://boxer.test.sneaksanddata.com")
|
69
69
|
pub_key = conn.get_consumer_public_key("app_consumer")
|
70
70
|
```
|
71
|
+
|
72
|
+
### Using as an authentication provider for other connectors
|
73
|
+
```python
|
74
|
+
from esd_services_api_client.boxer import BoxerConnector, RefreshableExternalTokenAuth, BoxerTokenAuth
|
75
|
+
from esd_services_api_client.crystal import CrystalConnector
|
76
|
+
|
77
|
+
auth_method = "example"
|
78
|
+
|
79
|
+
def get_external_token() -> str:
|
80
|
+
return "example_token"
|
81
|
+
|
82
|
+
# Configure authentication with boxer
|
83
|
+
external_auth = RefreshableExternalTokenAuth(lambda: get_external_token(), auth_method)
|
84
|
+
boxer_connector = BoxerConnector(base_url="https://example.com", auth=external_auth)
|
85
|
+
|
86
|
+
# Inject boxer auth to Crystal connector
|
87
|
+
connector = CrystalConnector(base_url="https://example.com", auth=BoxerTokenAuth(boxer_connector))
|
88
|
+
|
89
|
+
# Use Crystal connector with boxer auth
|
90
|
+
connector.await_runs("algorithm", ["id"])
|
91
|
+
```
|
@@ -18,6 +18,7 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
import base64
|
21
|
+
from abc import abstractmethod
|
21
22
|
from functools import partial
|
22
23
|
from typing import Callable, Any
|
23
24
|
|
@@ -75,12 +76,33 @@ class BoxerAuth(AuthBase):
|
|
75
76
|
return request
|
76
77
|
|
77
78
|
|
78
|
-
class
|
79
|
-
"""
|
79
|
+
class ExternalAuthBase(AuthBase):
|
80
|
+
"""Base class for external authentication methods"""
|
81
|
+
|
82
|
+
def __init__(self, authentication_provider):
|
83
|
+
self._authentication_provider = authentication_provider
|
84
|
+
|
85
|
+
@abstractmethod
|
86
|
+
def __call__(self, r: PreparedRequest) -> PreparedRequest:
|
87
|
+
pass
|
88
|
+
|
89
|
+
@property
|
90
|
+
def authentication_provider(self) -> str:
|
91
|
+
"""
|
92
|
+
:return authentication provider name
|
93
|
+
"""
|
94
|
+
return self._authentication_provider
|
95
|
+
|
96
|
+
|
97
|
+
class ExternalTokenAuth(ExternalAuthBase):
|
98
|
+
"""
|
99
|
+
Create authentication for external token e.g. for azuread or kubernetes auth policies
|
100
|
+
NOTE: this class is deprecated, use RefreshableExternalTokenAuth instead
|
101
|
+
"""
|
80
102
|
|
81
103
|
def __init__(self, token: str, authentication_provider: str):
|
104
|
+
super().__init__(authentication_provider)
|
82
105
|
self._token = token
|
83
|
-
self._authentication_provider = authentication_provider
|
84
106
|
|
85
107
|
def __call__(self, r: PreparedRequest) -> PreparedRequest:
|
86
108
|
"""
|
@@ -92,12 +114,55 @@ class ExternalTokenAuth(AuthBase):
|
|
92
114
|
r.headers["Authorization"] = f"Bearer {self._token}"
|
93
115
|
return r
|
94
116
|
|
95
|
-
|
96
|
-
|
117
|
+
|
118
|
+
class RefreshableExternalTokenAuth(ExternalAuthBase):
|
119
|
+
"""
|
120
|
+
Create authentication for external token e.g. for azuread or kubernetes auth policies
|
121
|
+
If the external token is expired, this auth method will try to get new external token and retry the request once
|
122
|
+
"""
|
123
|
+
|
124
|
+
def __init__(self, get_token: Callable[[], str], authentication_provider: str):
|
125
|
+
super().__init__(authentication_provider)
|
126
|
+
self._get_token = get_token
|
127
|
+
self._retrying = False
|
128
|
+
|
129
|
+
def __call__(self, r: PreparedRequest) -> PreparedRequest:
|
97
130
|
"""
|
98
|
-
|
131
|
+
Auth entrypoint
|
132
|
+
|
133
|
+
:param r: Request to authorize
|
134
|
+
:return: Request with Auth header set
|
99
135
|
"""
|
100
|
-
|
136
|
+
r.headers["Authorization"] = f"Bearer {self._get_token()}"
|
137
|
+
return r
|
138
|
+
|
139
|
+
def refresh_token(self, response: Response, session: Session, *_, **__):
|
140
|
+
"""
|
141
|
+
Refresh token hook if request fails with unauthorized or forbidden status code and retries the request.
|
142
|
+
:param response: Response received from API server
|
143
|
+
:param session: Session used for original API interaction
|
144
|
+
:param _: Positional arguments
|
145
|
+
:param __: Keyword arguments
|
146
|
+
:return:
|
147
|
+
"""
|
148
|
+
if self._retrying:
|
149
|
+
return response
|
150
|
+
if response.status_code == requests.codes["unauthorized"]:
|
151
|
+
self._retrying = True
|
152
|
+
response = session.send(self(response.request))
|
153
|
+
self._retrying = False
|
154
|
+
return response
|
155
|
+
return response
|
156
|
+
|
157
|
+
def get_refresh_hook(
|
158
|
+
self, session: Session
|
159
|
+
) -> Callable[[Response, Unpack[Any]], Response]:
|
160
|
+
"""
|
161
|
+
Generate request hook
|
162
|
+
:param session: Session used for original API interaction
|
163
|
+
:returns
|
164
|
+
"""
|
165
|
+
return partial(self.refresh_token, session=session)
|
101
166
|
|
102
167
|
|
103
168
|
class BoxerTokenAuth(AuthBase):
|
@@ -29,6 +29,8 @@ from esd_services_api_client.boxer._auth import (
|
|
29
29
|
BoxerAuth,
|
30
30
|
ExternalTokenAuth,
|
31
31
|
BoxerTokenAuth,
|
32
|
+
ExternalAuthBase,
|
33
|
+
RefreshableExternalTokenAuth,
|
32
34
|
)
|
33
35
|
from esd_services_api_client.boxer._helpers import (
|
34
36
|
_iterate_user_claims_response,
|
@@ -46,7 +48,7 @@ class BoxerConnector(BoxerTokenProvider):
|
|
46
48
|
self,
|
47
49
|
*,
|
48
50
|
base_url,
|
49
|
-
auth:
|
51
|
+
auth: ExternalAuthBase,
|
50
52
|
retry_attempts=10,
|
51
53
|
session: Optional[Session] = None,
|
52
54
|
):
|
@@ -59,6 +61,8 @@ class BoxerConnector(BoxerTokenProvider):
|
|
59
61
|
self.http.auth = auth or self._create_boxer_auth()
|
60
62
|
if auth:
|
61
63
|
self.authentication_provider = auth.authentication_provider
|
64
|
+
if isinstance(auth, RefreshableExternalTokenAuth):
|
65
|
+
self.http.hooks["response"].append(auth.get_refresh_hook(self.http))
|
62
66
|
self.retry_attempts = retry_attempts
|
63
67
|
|
64
68
|
def push_user_claim(self, claim: BoxerClaim, user_id: str):
|
@@ -185,8 +189,8 @@ def select_authentication(auth_provider: str, env: str) -> Optional[BoxerTokenAu
|
|
185
189
|
"""
|
186
190
|
if auth_provider == "azuread":
|
187
191
|
proteus_client = AzureClient(subscription_id="")
|
188
|
-
external_auth =
|
189
|
-
proteus_client.get_access_token
|
192
|
+
external_auth = RefreshableExternalTokenAuth(
|
193
|
+
proteus_client.get_access_token, auth_provider
|
190
194
|
)
|
191
195
|
boxer_connector = BoxerConnector(
|
192
196
|
base_url=f"https://boxer.{env}.sneaksanddata.com", auth=external_auth
|
@@ -1,14 +1,14 @@
|
|
1
1
|
esd_services_api_client/__init__.py,sha256=rP0njtEgVSMm-sOVayVfcRUrrubl4lme7HI2zS678Lo,598
|
2
|
-
esd_services_api_client/_version.py,sha256=
|
2
|
+
esd_services_api_client/_version.py,sha256=HSMl6bLm3r1Ias1jHIPpJeQ0IYNuuSdlT38MTb79ewM,22
|
3
3
|
esd_services_api_client/beast/__init__.py,sha256=XU4thkgkY6ZvT4yyDpaqeiIg3yotfcyJEewpo8iica4,743
|
4
4
|
esd_services_api_client/beast/_auth.py,sha256=V9m75EaFP8U_Ykf4DE5SWSSUrH8_UP_ugrmayJbwdmw,2666
|
5
5
|
esd_services_api_client/beast/_connector.py,sha256=_OGMr1qB1SyfMw0JLrCc2g7Ph4LrZ7JWa2etPbn2JTA,10505
|
6
6
|
esd_services_api_client/beast/_models.py,sha256=XOTZqr83mX44SpXG4KBDEHJozVuDQvQcaP_ctmS98hk,9438
|
7
|
-
esd_services_api_client/boxer/README.md,sha256=
|
7
|
+
esd_services_api_client/boxer/README.md,sha256=U8kXXtJFi1w0woQ4F_UOdDZiQl6-K7zFmQEUV4EktfM,2983
|
8
8
|
esd_services_api_client/boxer/__init__.py,sha256=OYsWvdnLan0kmjUcH4I2-m1rbPeARKp5iqhp8uyudPk,780
|
9
|
-
esd_services_api_client/boxer/_auth.py,sha256=
|
9
|
+
esd_services_api_client/boxer/_auth.py,sha256=vA7T9y0oZV2f17UWQ2or9CK8vAsNnHB10G5HNQe1l1I,7440
|
10
10
|
esd_services_api_client/boxer/_base.py,sha256=PSU08QzTKFkXfzx7fF5FIHBOZXshxNEd1J_qKGo0Rd0,976
|
11
|
-
esd_services_api_client/boxer/_connector.py,sha256=
|
11
|
+
esd_services_api_client/boxer/_connector.py,sha256=OBNQHlXHM3V6LWTlLFBpDBgS-m9Q3n-sLlqSGPAz4rQ,8476
|
12
12
|
esd_services_api_client/boxer/_helpers.py,sha256=hjf96CWYEH2iThYDcBB1iEGzalUWn-S9PZJzZJ6bdG0,1736
|
13
13
|
esd_services_api_client/boxer/_models.py,sha256=2tdVNRGQ0roR3THfzTq7KF2eQ5mS30PbxpqYhPm1y6A,3105
|
14
14
|
esd_services_api_client/common/__init__.py,sha256=rP0njtEgVSMm-sOVayVfcRUrrubl4lme7HI2zS678Lo,598
|
@@ -16,7 +16,7 @@ esd_services_api_client/crystal/__init__.py,sha256=afSGQRkDic0ECsJfgu3b291kX8CyU
|
|
16
16
|
esd_services_api_client/crystal/_api_versions.py,sha256=2BMiQRS0D8IEpWCCys3dge5alVBRCZrOuCR1QAn8UIM,832
|
17
17
|
esd_services_api_client/crystal/_connector.py,sha256=lWWKhVKvaFtLTsl6abtydFH4rsMoCATD_IMpVOARyl0,12150
|
18
18
|
esd_services_api_client/crystal/_models.py,sha256=eRhGAl8LjglCyIFwf1bcFBhjbpSuRYucuF2LO388L2E,4025
|
19
|
-
esd_services_api_client-0.9.
|
20
|
-
esd_services_api_client-0.9.
|
21
|
-
esd_services_api_client-0.9.
|
22
|
-
esd_services_api_client-0.9.
|
19
|
+
esd_services_api_client-0.9.2.dist-info/LICENSE,sha256=0gS6zXsPp8qZhzi1xaGCIYPzb_0e8on7HCeFJe8fOpw,10693
|
20
|
+
esd_services_api_client-0.9.2.dist-info/METADATA,sha256=aMe49RZg_WaTlwlwSvtaxyWYOmJOhF6WDN7-MZpaqyc,1075
|
21
|
+
esd_services_api_client-0.9.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
22
|
+
esd_services_api_client-0.9.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|