ibm-cloud-sdk-core 3.23.0__py3-none-any.whl → 3.24.1__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.
@@ -46,6 +46,7 @@ from .token_managers.cp4d_token_manager import CP4DTokenManager
46
46
  from .token_managers.container_token_manager import ContainerTokenManager
47
47
  from .token_managers.vpc_instance_token_manager import VPCInstanceTokenManager
48
48
  from .token_managers.mcsp_token_manager import MCSPTokenManager
49
+ from .token_managers.mcspv2_token_manager import MCSPV2TokenManager
49
50
  from .api_exception import ApiException
50
51
  from .utils import datetime_to_string, string_to_datetime, read_external_sources
51
52
  from .utils import datetime_to_string_list, string_to_datetime_list
@@ -28,9 +28,14 @@ classes:
28
28
  Authenticator: Abstract Base Class. Implement this interface to provide custom authentication schemes to services.
29
29
  BasicAuthenticator: Authenticator for passing supplied basic authentication information to service endpoint.
30
30
  BearerTokenAuthenticator: Authenticator for passing supplied bearer token to service endpoint.
31
+ ContainerAuthenticator: Authenticator for use in a container environment.
31
32
  CloudPakForDataAuthenticator: Authenticator for passing CP4D authentication information to service endpoint.
32
33
  IAMAuthenticator: Authenticator for passing IAM authentication information to service endpoint.
34
+ IAMAssumeAuthenticator: Authenticator for the "assume" grant type.
35
+ VPCInstanceAuthenticator: Authenticator for use within a VPC instance.
33
36
  NoAuthAuthenticator: Performs no authentication. Useful for testing purposes.
37
+ MCSPAuthenticator: Authenticator that supports the MCSP v1 token exchange.
38
+ MCSPV2Authenticator: Authenticator that supports the MCSP v2 token exchange.
34
39
  """
35
40
 
36
41
  from .authenticator import Authenticator
@@ -43,3 +48,4 @@ from .iam_assume_authenticator import IAMAssumeAuthenticator
43
48
  from .vpc_instance_authenticator import VPCInstanceAuthenticator
44
49
  from .no_auth_authenticator import NoAuthAuthenticator
45
50
  from .mcsp_authenticator import MCSPAuthenticator
51
+ from .mcspv2_authenticator import MCSPV2Authenticator
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- # Copyright 2019, 2023 IBM All Rights Reserved.
3
+ # Copyright 2019, 2025 IBM All Rights Reserved.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ class Authenticator(ABC):
30
30
  AUTHTYPE_VPC = 'vpc'
31
31
  AUTHTYPE_NOAUTH = 'noAuth'
32
32
  AUTHTYPE_MCSP = 'mcsp'
33
+ AUTHTYPE_MCSPV2 = 'mcspv2'
33
34
  AUTHTYPE_UNKNOWN = 'unknown'
34
35
 
35
36
  @abstractmethod
@@ -0,0 +1,270 @@
1
+ # coding: utf-8
2
+
3
+ # Copyright 2025. IBM All Rights Reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ from typing import Dict, Optional
18
+
19
+ from requests import Request
20
+
21
+ from ibm_cloud_sdk_core.logger import get_logger
22
+ from .authenticator import Authenticator
23
+ from ..token_managers.mcspv2_token_manager import MCSPV2TokenManager
24
+
25
+ logger = get_logger()
26
+
27
+
28
+ class MCSPV2Authenticator(Authenticator):
29
+ """The MCSPV2Authenticator invokes the MCSP v2 token-exchange operation
30
+ (POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token) to obtain an access token
31
+ for an apikey, and adds the access token to requests via an Authorization header
32
+ of the form: "Authorization: Bearer <access-token>".
33
+
34
+ Keyword Args:
35
+ apikey: The apikey used to obtain an access token [required].
36
+ url: The base endpoint URL for the MCSP token service [required].
37
+ scope_collection_type: The scope collection type of item(s) [required].
38
+ Valid values are: "accounts", "subscriptions", "services".
39
+ scope_id: The scope identifier of item(s) [required].
40
+ include_builtin_actions: A flag to include builtin actions in the "actions" claim in the
41
+ MCSP access token (default: False).
42
+ include_custom_actions: A flag to include custom actions in the "actions" claim in the
43
+ MCSP access token (default: False).
44
+ include_roles: A flag to include the "roles" claim in the MCSP access token (default: True).
45
+ prefix_roles: A flag to add a prefix with the scope level where the role is defined
46
+ in the "roles" claim (default: False).
47
+ caller_ext_claim: A map (dictionary) containing keys and values to be injected into
48
+ the access token as the "callerExt" claim (default: None).
49
+ The keys used in this map must be enabled in the apikey by setting the
50
+ "callerExtClaimNames" property when the apikey is created.
51
+ This property is typically only used in scenarios involving an apikey with identityType `SERVICEID`.
52
+ disable_ssl_verification: A flag that indicates whether verification of the server's SSL
53
+ certificate should be disabled or not (default: False).
54
+ headers: Default headers to be sent with every MCSP token request (default: None).
55
+ proxies: Dictionary for mapping request protocol to proxy URL (default: None).
56
+ proxies.http (optional): The proxy endpoint to use for HTTP requests.
57
+ proxies.https (optional): The proxy endpoint to use for HTTPS requests.
58
+
59
+ Attributes:
60
+ token_manager (MCSPTokenManager): Retrieves and manages MCSP tokens from the endpoint specified by the url.
61
+
62
+ Raises:
63
+ TypeError: The `disable_ssl_verification` is not a bool.
64
+ ValueError: An error occurred while validating the configuration.
65
+ """
66
+
67
+ def __init__(
68
+ self,
69
+ *,
70
+ apikey: str,
71
+ url: str,
72
+ scope_collection_type: str,
73
+ scope_id: str,
74
+ include_builtin_actions: bool = False,
75
+ include_custom_actions: bool = False,
76
+ include_roles: bool = True,
77
+ prefix_roles: bool = False,
78
+ caller_ext_claim: Optional[Dict[str, str]] = None,
79
+ disable_ssl_verification: bool = False,
80
+ headers: Optional[Dict[str, str]] = None,
81
+ proxies: Optional[Dict[str, str]] = None,
82
+ ) -> None:
83
+
84
+ self.token_manager = MCSPV2TokenManager(
85
+ apikey=apikey,
86
+ url=url,
87
+ scope_collection_type=scope_collection_type,
88
+ scope_id=scope_id,
89
+ include_builtin_actions=include_builtin_actions,
90
+ include_custom_actions=include_custom_actions,
91
+ include_roles=include_roles,
92
+ prefix_roles=prefix_roles,
93
+ caller_ext_claim=caller_ext_claim,
94
+ disable_ssl_verification=disable_ssl_verification,
95
+ headers=headers,
96
+ proxies=proxies,
97
+ )
98
+ self.validate()
99
+
100
+ def authentication_type(self) -> str:
101
+ """Returns this authenticator's type ('mcsp')."""
102
+ return Authenticator.AUTHTYPE_MCSPV2
103
+
104
+ def validate(self) -> None:
105
+ """Validate the configuration.
106
+
107
+ Raises:
108
+ ValueError: The <...> property shouldn't be None.
109
+ """
110
+ if not isinstance(self.token_manager.apikey, str):
111
+ raise TypeError('"apikey" must be a string')
112
+ if not isinstance(self.token_manager.url, str):
113
+ raise TypeError('"url" must be a string')
114
+ if not isinstance(self.token_manager.scope_collection_type, str):
115
+ raise TypeError('"scope_collection_type" must be a string')
116
+ if not isinstance(self.token_manager.scope_id, str):
117
+ raise TypeError('"scope_id" must be a string')
118
+ if not isinstance(self.token_manager.include_builtin_actions, bool):
119
+ raise TypeError('"include_builtin_actions" must be a bool')
120
+ if not isinstance(self.token_manager.include_custom_actions, bool):
121
+ raise TypeError('"include_custom_actions" must be a bool')
122
+ if not isinstance(self.token_manager.include_roles, bool):
123
+ raise TypeError('"include_roles" must be a bool')
124
+ if not isinstance(self.token_manager.prefix_roles, bool):
125
+ raise TypeError('"prefix_roles" must be a bool')
126
+ if not isinstance(self.token_manager.caller_ext_claim, (dict, type(None))):
127
+ raise TypeError('"caller_ext_claim" must be a dictionary or None')
128
+ if not isinstance(self.token_manager.disable_ssl_verification, bool):
129
+ raise TypeError('"disable_ssl_verification" must be a bool')
130
+ if not isinstance(self.token_manager.headers, (dict, type(None))):
131
+ raise TypeError('"headers" must be a dictionary or None')
132
+ if not isinstance(self.token_manager.proxies, (dict, type(None))):
133
+ raise TypeError('"proxies" must be a dictionary or None')
134
+
135
+ def authenticate(self, req: Request) -> None:
136
+ """Adds MCSP authentication information to the request.
137
+
138
+ The MCSP bearer token will be added to the request's headers in the form:
139
+ Authorization: Bearer <bearer-token>
140
+
141
+ Args:
142
+ req: The request to add MCSP authentication information to. Must contain a key to a dictionary
143
+ called headers.
144
+ """
145
+ headers = req.get('headers')
146
+ bearer_token = self.token_manager.get_token()
147
+ headers['Authorization'] = 'Bearer {0}'.format(bearer_token)
148
+ logger.debug('Authenticated outbound request (type=%s)', self.authentication_type())
149
+
150
+ def set_scope_collection_type(self, scope_collection_type: str) -> None:
151
+ """Set the scope_collection_type value.
152
+
153
+ Args:
154
+ scope_collection_type: the value to set.
155
+
156
+ Raises:
157
+ TypeError: "scope_collection_type" must be a string.
158
+ """
159
+ if not isinstance(scope_collection_type, str):
160
+ raise TypeError('"scope_collection_type" must be a string')
161
+ self.token_manager.scope_collection_type = scope_collection_type
162
+
163
+ def set_scope_id(self, scope_id: str) -> None:
164
+ """Set the scope_id value.
165
+
166
+ Args:
167
+ scope_id: the value to set.
168
+
169
+ Raises:
170
+ TypeError: "scope_id" must be a string.
171
+ """
172
+ if not isinstance(scope_id, str):
173
+ raise TypeError('"scope_id" must be a string')
174
+ self.token_manager.scope_id = scope_id
175
+
176
+ def set_include_builtin_actions(self, include_builtin_actions: bool = False) -> None:
177
+ """Set the include_builtin_actions flag.
178
+
179
+ Args:
180
+ include_builtin_actions: The value to set (default: False).
181
+
182
+ Raises:
183
+ TypeError: "include_builtin_actions" must be a bool.
184
+ """
185
+ if not isinstance(include_builtin_actions, bool):
186
+ raise TypeError('"include_builtin_actions" must be a bool')
187
+ self.token_manager.include_builtin_actions = include_builtin_actions
188
+
189
+ def set_include_custom_actions(self, include_custom_actions: bool = False) -> None:
190
+ """Set the include_custom_actions flag.
191
+
192
+ Args:
193
+ include_custom_actions: The value to set (default: False).
194
+
195
+ Raises:
196
+ TypeError: "include_custom_actions" must be a bool.
197
+ """
198
+ if not isinstance(include_custom_actions, bool):
199
+ raise TypeError('"include_custom_actions" must be a bool')
200
+ self.token_manager.include_custom_actions = include_custom_actions
201
+
202
+ def set_include_roles(self, include_roles: bool = True) -> None:
203
+ """Set the include_roles flag.
204
+
205
+ Args:
206
+ include_roles: The value to set (default: True).
207
+
208
+ Raises:
209
+ TypeError: "include_roles" must be a bool.
210
+ """
211
+ if not isinstance(include_roles, bool):
212
+ raise TypeError('"include_roles" must be a bool')
213
+ self.token_manager.include_roles = include_roles
214
+
215
+ def set_prefix_roles(self, prefix_roles: bool = False) -> None:
216
+ """Set the prefix_roles flag.
217
+
218
+ Args:
219
+ prefix_roles: The value to set (default: False).
220
+
221
+ Raises:
222
+ TypeError: "prefix_roles" must be a bool.
223
+ """
224
+ if not isinstance(prefix_roles, bool):
225
+ raise TypeError('"prefix_roles" must be a bool')
226
+ self.token_manager.prefix_roles = prefix_roles
227
+
228
+ def set_caller_ext_claim(self, caller_ext_claim: Optional[Dict[str, str]] = None) -> None:
229
+ """Set the caller_ext_claim value.
230
+
231
+ Args:
232
+ caller_ext_claim: The value to set (default: False).
233
+
234
+ Raises:
235
+ TypeError: "caller_ext_claim" must be a dictionary or None.
236
+ """
237
+ if not isinstance(caller_ext_claim, (dict, type(None))):
238
+ raise TypeError('"caller_ext_claim" must be a dictionary or None')
239
+ self.token_manager.caller_ext_claim = caller_ext_claim
240
+
241
+ def set_disable_ssl_verification(self, disable_ssl_verification: bool = False) -> None:
242
+ """Set the disable_ssl_verification flag.
243
+
244
+ Args:
245
+ disable_ssl_verification: The value to set (default: False).
246
+
247
+ Raises:
248
+ TypeError: "disable_ssl_verification" must be a bool.
249
+ """
250
+ if not isinstance(disable_ssl_verification, bool):
251
+ raise TypeError('"disable_ssl_verification" must be a bool')
252
+ self.token_manager.disable_ssl_verification = disable_ssl_verification
253
+
254
+ def set_headers(self, headers: Optional[Dict[str, str]] = None) -> None:
255
+ """Set the headers to be sent with each MCSP token-exchange request.
256
+
257
+ Args:
258
+ headers: The headers to be sent with each MCSP token request (default: None).
259
+ """
260
+ self.token_manager.set_headers(headers)
261
+
262
+ def set_proxies(self, proxies: Optional[Dict[str, str]] = None) -> None:
263
+ """Sets the proxies the token manager will use to communicate with MCSP on behalf of the host.
264
+
265
+ Args:
266
+ proxies: Dictionary for mapping request protocol to proxy URL (default: None).
267
+ proxies.http (optional): The proxy endpoint to use for HTTP requests.
268
+ proxies.https (optional): The proxy endpoint to use for HTTPS requests.
269
+ """
270
+ self.token_manager.set_proxies(proxies)
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- # Copyright 2019, 2024 IBM All Rights Reserved.
3
+ # Copyright 2019, 2025 IBM All Rights Reserved.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
+ import json
17
18
  from .authenticators import (
18
19
  Authenticator,
19
20
  BasicAuthenticator,
@@ -25,8 +26,9 @@ from .authenticators import (
25
26
  NoAuthAuthenticator,
26
27
  VPCInstanceAuthenticator,
27
28
  MCSPAuthenticator,
29
+ MCSPV2Authenticator,
28
30
  )
29
- from .utils import read_external_sources
31
+ from .utils import read_external_sources, string_to_bool
30
32
  from .logger import get_logger
31
33
 
32
34
  logger = get_logger()
@@ -57,6 +59,7 @@ def get_authenticator_from_environment(service_name: str) -> Authenticator:
57
59
 
58
60
 
59
61
  # pylint: disable=too-many-branches
62
+ # pylint: disable=too-many-statements
60
63
  def __construct_authenticator(config: dict) -> Authenticator:
61
64
  # Determine the authentication type if not specified explicitly.
62
65
  if config.get('AUTH_TYPE'):
@@ -86,7 +89,7 @@ def __construct_authenticator(config: dict) -> Authenticator:
86
89
  url=config.get('AUTH_URL'),
87
90
  client_id=config.get('CLIENT_ID'),
88
91
  client_secret=config.get('CLIENT_SECRET'),
89
- disable_ssl_verification=config.get('AUTH_DISABLE_SSL', 'false').lower() == 'true',
92
+ disable_ssl_verification=string_to_bool(config.get('AUTH_DISABLE_SSL', 'false')),
90
93
  scope=config.get('SCOPE'),
91
94
  )
92
95
  elif auth_type == Authenticator.AUTHTYPE_CP4D.lower():
@@ -95,7 +98,7 @@ def __construct_authenticator(config: dict) -> Authenticator:
95
98
  password=config.get('PASSWORD'),
96
99
  url=config.get('AUTH_URL'),
97
100
  apikey=config.get('APIKEY'),
98
- disable_ssl_verification=config.get('AUTH_DISABLE_SSL', 'false').lower() == 'true',
101
+ disable_ssl_verification=string_to_bool(config.get('AUTH_DISABLE_SSL', 'false')),
99
102
  )
100
103
  elif auth_type == Authenticator.AUTHTYPE_IAM.lower() and config.get('APIKEY'):
101
104
  authenticator = IAMAuthenticator(
@@ -103,7 +106,7 @@ def __construct_authenticator(config: dict) -> Authenticator:
103
106
  url=config.get('AUTH_URL'),
104
107
  client_id=config.get('CLIENT_ID'),
105
108
  client_secret=config.get('CLIENT_SECRET'),
106
- disable_ssl_verification=config.get('AUTH_DISABLE_SSL', 'false').lower() == 'true',
109
+ disable_ssl_verification=string_to_bool(config.get('AUTH_DISABLE_SSL', 'false')),
107
110
  scope=config.get('SCOPE'),
108
111
  )
109
112
  elif auth_type == Authenticator.AUTHTYPE_IAM_ASSUME.lower():
@@ -116,7 +119,7 @@ def __construct_authenticator(config: dict) -> Authenticator:
116
119
  url=config.get('AUTH_URL'),
117
120
  client_id=config.get('CLIENT_ID'),
118
121
  client_secret=config.get('CLIENT_SECRET'),
119
- disable_ssl_verification=config.get('AUTH_DISABLE_SSL', 'false').lower() == 'true',
122
+ disable_ssl_verification=string_to_bool(config.get('AUTH_DISABLE_SSL', 'false')),
120
123
  scope=config.get('SCOPE'),
121
124
  )
122
125
  elif auth_type == Authenticator.AUTHTYPE_VPC.lower():
@@ -130,6 +133,48 @@ def __construct_authenticator(config: dict) -> Authenticator:
130
133
  apikey=config.get('APIKEY'),
131
134
  url=config.get('AUTH_URL'),
132
135
  )
136
+ elif auth_type == Authenticator.AUTHTYPE_MCSPV2.lower():
137
+ # Required arguments.
138
+ apikey = config.get('APIKEY')
139
+ url = config.get('AUTH_URL')
140
+ scope_collection_type = config.get('SCOPE_COLLECTION_TYPE')
141
+ scope_id = config.get('SCOPE_ID')
142
+
143
+ # Optional arguments.
144
+ optional_args = {}
145
+ str_value = config.get("INCLUDE_BUILTIN_ACTIONS")
146
+ if str_value is not None:
147
+ optional_args['include_builtin_actions'] = string_to_bool(str_value)
148
+
149
+ str_value = config.get("INCLUDE_CUSTOM_ACTIONS")
150
+ if str_value is not None:
151
+ optional_args['include_custom_actions'] = string_to_bool(str_value)
152
+
153
+ str_value = config.get("INCLUDE_ROLES")
154
+ if str_value is not None:
155
+ optional_args['include_roles'] = string_to_bool(str_value)
156
+
157
+ str_value = config.get("PREFIX_ROLES")
158
+ if str_value is not None:
159
+ optional_args['prefix_roles'] = string_to_bool(str_value)
160
+
161
+ str_value = config.get("CALLER_EXT_CLAIM")
162
+ if str_value is not None:
163
+ try:
164
+ optional_args['caller_ext_claim'] = json.loads(str_value)
165
+ except Exception as caused_by:
166
+ msg = 'An error occurred while unmarshalling the CALLER_EXT_CLAIM configuration property: {0}'.format(
167
+ str_value
168
+ )
169
+ raise ValueError(msg) from caused_by
170
+
171
+ str_value = config.get("AUTH_DISABLE_SSL")
172
+ if str_value is not None:
173
+ optional_args['disable_ssl_verification'] = string_to_bool(str_value)
174
+
175
+ authenticator = MCSPV2Authenticator(
176
+ apikey=apikey, url=url, scope_collection_type=scope_collection_type, scope_id=scope_id, **optional_args
177
+ )
133
178
  elif auth_type == Authenticator.AUTHTYPE_NOAUTH.lower():
134
179
  authenticator = NoAuthAuthenticator()
135
180
 
@@ -0,0 +1,185 @@
1
+ # coding: utf-8
2
+
3
+ # Copyright 2025. IBM All Rights Reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ import json
18
+ from typing import Dict, List, Optional
19
+ import requests
20
+
21
+ from ibm_cloud_sdk_core.logger import get_logger
22
+ from ..private_helpers import _build_user_agent
23
+ from .jwt_token_manager import JWTTokenManager
24
+
25
+ logger = get_logger()
26
+
27
+
28
+ class MCSPV2TokenManager(JWTTokenManager):
29
+ """The MCSPV2TokenManager invokes the MCSP v2 token-exchange operation
30
+ (POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token) to obtain an access token
31
+ for an apikey. When the access token expires, a new access token is obtained from the token server.
32
+
33
+ Keyword Arguments:
34
+ apikey: The apikey for authentication [required].
35
+ url: The endpoint for JWT token requests [required].
36
+ scope_collection_type: The scope collection type of item(s) [required].
37
+ Valid values are: "accounts", "subscriptions", "services".
38
+ scope_id: The scope identifier of item(s) [required].
39
+ include_builtin_actions: A flag to include builtin actions in the "actions" claim in the
40
+ MCSP access token (default: False).
41
+ include_custom_actions: A flag to include custom actions in the "actions" claim in the
42
+ MCSP access token (default: False).
43
+ include_roles: A flag to include the "roles" claim in the MCSP access token (default: True).
44
+ prefix_roles: A flag to add a prefix with the scope level where the role is defined
45
+ in the "roles" claim (default: False).
46
+ caller_ext_claim: A dictionary (map) containing keys and values to be injected into
47
+ the access token as the "callerExt" claim (default: None).
48
+ The keys used in this map must be enabled in the apikey by setting the
49
+ "callerExtClaimNames" property when the apikey is created.
50
+ disable_ssl_verification: Disable ssl verification. Defaults to False.
51
+ headers: Headers to be sent with every service token request. Defaults to None.
52
+ proxies: Proxies to use for making request. Defaults to None.
53
+ proxies.http (optional): The proxy endpoint to use for HTTP requests.
54
+ proxies.https (optional): The proxy endpoint to use for HTTPS requests.
55
+ """
56
+
57
+ # pylint: disable=too-many-instance-attributes
58
+
59
+ # The name of the response body property that contains the access token.
60
+ TOKEN_NAME = 'token'
61
+
62
+ # The path associated with the token-exchange operation to be invoked.
63
+ OPERATION_PATH = '/api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token'
64
+
65
+ # These path parameter names must be kept in sync with the operation path above.
66
+ _path_param_names = ['scopeCollectionType', 'scopeId']
67
+
68
+ def __init__(
69
+ self,
70
+ *,
71
+ apikey: str,
72
+ url: str,
73
+ scope_collection_type: str,
74
+ scope_id: str,
75
+ include_builtin_actions: bool = False,
76
+ include_custom_actions: bool = False,
77
+ include_roles: bool = True,
78
+ prefix_roles: bool = False,
79
+ caller_ext_claim: Optional[Dict[str, str]] = None,
80
+ disable_ssl_verification: bool = False,
81
+ headers: Optional[Dict[str, str]] = None,
82
+ proxies: Optional[Dict[str, str]] = None,
83
+ ) -> None:
84
+ self.apikey = apikey
85
+ self.scope_collection_type = scope_collection_type
86
+ self.scope_id = scope_id
87
+ self.include_builtin_actions = include_builtin_actions
88
+ self.include_custom_actions = include_custom_actions
89
+ self.include_roles = include_roles
90
+ self.prefix_roles = prefix_roles
91
+ self.caller_ext_claim = caller_ext_claim
92
+
93
+ self.set_headers(headers)
94
+ self.set_proxies(proxies)
95
+
96
+ super().__init__(url, disable_ssl_verification=disable_ssl_verification, token_name=self.TOKEN_NAME)
97
+ self._set_user_agent(_build_user_agent('mcspv2-authenticator'))
98
+
99
+ def set_headers(self, headers: Optional[Dict[str, str]] = None) -> None:
100
+ """Headers to be sent with every MCSP token request.
101
+
102
+ Args:
103
+ headers: The headers to be sent with every MCSP token request (default: None).
104
+ """
105
+ if isinstance(headers, (dict, type(None))):
106
+ self.headers = headers
107
+ else:
108
+ raise TypeError('"headers" must be a dictionary or None')
109
+
110
+ def set_proxies(self, proxies: Optional[Dict[str, str]] = None) -> None:
111
+ """Sets the proxies the token manager will use to communicate with MCSP on behalf of the host.
112
+
113
+ Args:
114
+ proxies: Proxies to use for making request (default: None).
115
+ proxies.http (optional): The proxy endpoint to use for HTTP requests.
116
+ proxies.https (optional): The proxy endpoint to use for HTTPS requests.
117
+ """
118
+ if isinstance(proxies, (dict, type(None))):
119
+ self.proxies = proxies
120
+ else:
121
+ raise TypeError('"proxies" must be a dictionary or None')
122
+
123
+ def request_token(self) -> dict:
124
+ """Invokes the "POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token" operation
125
+ to obtain an access token."""
126
+
127
+ # These headers take priority over user-supplied headers.
128
+ required_headers = {
129
+ 'User-Agent': self.user_agent,
130
+ 'Content-Type': 'application/json',
131
+ 'Accept': 'application/json',
132
+ }
133
+
134
+ # Set up the request headers.
135
+ request_headers = {}
136
+ if self.headers is not None and isinstance(self.headers, dict):
137
+ request_headers.update(self.headers)
138
+ request_headers.update(required_headers)
139
+
140
+ # Compute the request URL.
141
+ path_param_values = self._encode_path_vars(self.scope_collection_type, self.scope_id)
142
+ path_params = dict(zip(self._path_param_names, path_param_values))
143
+ request_url = self.url + self.OPERATION_PATH.format(**path_params)
144
+
145
+ # Create the request body (apikey, callerExtClaim properties).
146
+ request_body = {}
147
+ request_body['apikey'] = self.apikey
148
+ if self.caller_ext_claim is not None and isinstance(self.caller_ext_claim, dict):
149
+ request_body['callerExtClaim'] = self.caller_ext_claim
150
+
151
+ # Set up the query params.
152
+ query_params = {
153
+ 'includeBuiltinActions': self.bool_to_string(self.include_builtin_actions),
154
+ 'includeCustomActions': self.bool_to_string(self.include_custom_actions),
155
+ 'includeRoles': self.bool_to_string(self.include_roles),
156
+ 'prefixRolesWithDefinitionScope': self.bool_to_string(self.prefix_roles),
157
+ }
158
+
159
+ logger.debug('Invoking MCSP v2 token service operation: %s', request_url)
160
+
161
+ response = self._request(
162
+ method='POST',
163
+ headers=request_headers,
164
+ url=request_url,
165
+ params=query_params,
166
+ data=json.dumps(request_body),
167
+ proxies=self.proxies,
168
+ )
169
+ logger.debug('Returned from MCSP v2 token service operation')
170
+ return response
171
+
172
+ def _encode_path_vars(self, *args: str) -> List[str]:
173
+ """Encode path variables to be substituted into a URL path.
174
+
175
+ Arguments:
176
+ args: A list of strings to be URL path encoded
177
+
178
+ Returns:
179
+ A list of encoded strings that are safe to substitute into a URL path.
180
+ """
181
+ return (requests.utils.quote(x, safe='') for x in args)
182
+
183
+ def bool_to_string(self, value: bool) -> str:
184
+ """Convert a boolean value to string."""
185
+ return 'true' if value else 'false'
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- # Copyright 2019, 2024 IBM All Rights Reserved.
3
+ # Copyright 2019, 2025 IBM All Rights Reserved.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -273,6 +273,18 @@ def string_to_date(string: str) -> datetime.date:
273
273
  return date_parser.parse(string).date()
274
274
 
275
275
 
276
+ def string_to_bool(string: str) -> bool:
277
+ """Converts 'string' to a bool value.
278
+ Args:
279
+ string: the value to convert. This should be some form of "true" or "false"
280
+ (e.g. "True", "TrUE", "False", "FaLsE", etc.)
281
+
282
+ Returns:
283
+ the boolean value
284
+ """
285
+ return string.strip().lower() == 'true'
286
+
287
+
276
288
  def get_query_param(url_str: str, param: str) -> str:
277
289
  """Return a query parameter value from url_str
278
290
 
@@ -1 +1 @@
1
- __version__ = '3.23.0'
1
+ __version__ = '3.24.1'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ibm-cloud-sdk-core
3
- Version: 3.23.0
3
+ Version: 3.24.1
4
4
  Summary: Core library used by SDKs for IBM Cloud Services
5
5
  Author-email: IBM <devxsdk@us.ibm.com>
6
6
  Project-URL: Repository, https://github.com/IBM/python-sdk-core
@@ -42,6 +42,7 @@ Requires-Dist: black<25.0.0,>=24.0.0; extra == "dev"
42
42
  Provides-Extra: publish
43
43
  Requires-Dist: build; extra == "publish"
44
44
  Requires-Dist: twine; extra == "publish"
45
+ Dynamic: license-file
45
46
 
46
47
  [![Build Status](https://github.com/IBM/python-sdk-core/actions/workflows/build.yaml/badge.svg)](https://github.com/IBM/python-sdk-core/actions/workflows/build.yaml)
47
48
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ibm-cloud-sdk-core)](https://pypi.org/project/ibm-cloud-sdk-core/)
@@ -49,7 +50,7 @@ Requires-Dist: twine; extra == "publish"
49
50
  [![CLA assistant](https://cla-assistant.io/readme/badge/ibm/python-sdk-core)](https://cla-assistant.io/ibm/python-sdk-core)
50
51
  [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
51
52
 
52
- # IBM Python SDK Core Version 3.23.0
53
+ # IBM Python SDK Core Version 3.24.1
53
54
  This project contains core functionality required by Python code generated by the IBM Cloud OpenAPI SDK Generator
54
55
  (openapi-sdkgen).
55
56
 
@@ -115,12 +116,12 @@ When running your application, you should see output like this if debug logging
115
116
  ```
116
117
  2024-09-16 15:44:45,174 [ibm-cloud-sdk-core:DEBUG] Get authenticator from environment, key=global_search
117
118
  2024-09-16 15:44:45,175 [ibm-cloud-sdk-core:DEBUG] Set service URL: https://api.global-search-tagging.cloud.ibm.com
118
- 2024-09-16 15:44:45,175 [ibm-cloud-sdk-core:DEBUG] Set User-Agent: ibm-python-sdk-core-3.23.0 os.name=Linux os.version=6.10.9-100.fc39.x86_64 python.version=3.12.5
119
+ 2024-09-16 15:44:45,175 [ibm-cloud-sdk-core:DEBUG] Set User-Agent: ibm-python-sdk-core-3.24.1 os.name=Linux os.version=6.10.9-100.fc39.x86_64 python.version=3.12.5
119
120
  2024-09-16 15:44:45,181 [ibm-cloud-sdk-core:DEBUG] Configuring BaseService instance with service name: global_search
120
121
  2024-09-16 15:44:45,181 [ibm-cloud-sdk-core:DEBUG] Performing synchronous token fetch
121
122
  2024-09-16 15:44:45,182 [ibm-cloud-sdk-core:DEBUG] Invoking IAM get_token operation: https://iam.cloud.ibm.com/identity/token
122
123
  2024-09-16 15:44:45,182 [urllib3.connectionpool:DEBUG] Starting new HTTPS connection (1): iam.cloud.ibm.com:443
123
- send: b'POST /identity/token HTTP/1.1\r\nHost: iam.cloud.ibm.com\r\nUser-Agent: ibm-python-sdk-core/iam-authenticator-3.23.0 os.name=Linux os.version=6.10.9-100.fc39.x86_64 python.version=3.12.5\r\nAccept-Encoding: gzip, deflate\r\nAccept: application/json\r\nConnection: keep-alive\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 135\r\n\r\n'
124
+ send: b'POST /identity/token HTTP/1.1\r\nHost: iam.cloud.ibm.com\r\nUser-Agent: ibm-python-sdk-core/iam-authenticator-3.24.1 os.name=Linux os.version=6.10.9-100.fc39.x86_64 python.version=3.12.5\r\nAccept-Encoding: gzip, deflate\r\nAccept: application/json\r\nConnection: keep-alive\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 135\r\n\r\n'
124
125
  send: b'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=[redacted]&response_type=cloud_iam'
125
126
  reply: 'HTTP/1.1 200 OK\r\n'
126
127
  header: Content-Type: application/json
@@ -1,15 +1,15 @@
1
- ibm_cloud_sdk_core/__init__.py,sha256=eC0K027znbykBluNB7Vd3PlBAvxlH0VG3DexknrlKfc,3028
1
+ ibm_cloud_sdk_core/__init__.py,sha256=l3Gn6TD8aassVAb_1K5dDMSEv6lLw8KBA1xkOjkFGUs,3096
2
2
  ibm_cloud_sdk_core/api_exception.py,sha256=YNd7Dg_yiwcHk-AA-suNlivgyrA9A32Do1qtYeKzuWc,3654
3
3
  ibm_cloud_sdk_core/base_service.py,sha256=Xn36CiuH4Dhm34Uf8D82p2QDmSlO9bKvJ2DwgqwJHtg,22081
4
4
  ibm_cloud_sdk_core/detailed_response.py,sha256=agLMQ-Mh3bU_lLnSnSO1SwjuNBPQj8plO8ew2xXWL6I,3101
5
- ibm_cloud_sdk_core/get_authenticator.py,sha256=Ozw0JVjnzXQAoUAJQ_gg780AZTg08O2JKlJSkTZuSnU,5581
5
+ ibm_cloud_sdk_core/get_authenticator.py,sha256=8GqoUTotrWsuNNA8xyyGkRLBBuWinve7n8eucMfmzHo,7429
6
6
  ibm_cloud_sdk_core/http_adapter.py,sha256=nRUvt7hbSC8Vyhqe_oA5k_NKoRMM-S4VCSAZVQ-AHQU,1075
7
7
  ibm_cloud_sdk_core/logger.py,sha256=sdDNAA9LlpynadFxTRsCWfqSNBrN6uKMxVsFuo2PnIo,2708
8
8
  ibm_cloud_sdk_core/private_helpers.py,sha256=5ei9gNwuN-inNJ2WqMXcXEPfLM1NALOLi4ucLMcYohY,1181
9
- ibm_cloud_sdk_core/utils.py,sha256=13sHWir3xvp5eJ2JE7FIdAXgQHOKCLlKGk_R-R5W2Ms,15828
10
- ibm_cloud_sdk_core/version.py,sha256=DvtLj8y3NnuyAfiEpmunbiI1RVU8CwfOkrdPwsMCoYc,23
11
- ibm_cloud_sdk_core/authenticators/__init__.py,sha256=hIlEbbNC_OLwnD5C8p752CFhE_W45X4IsTc9LvOaRr4,2194
12
- ibm_cloud_sdk_core/authenticators/authenticator.py,sha256=ml3JFqZPmARESdT-F1qqYfZcvyLc3-1WU5CGNwKi78U,2017
9
+ ibm_cloud_sdk_core/utils.py,sha256=-vi21lStgoAxJWK4G4jkV5bmqypwxzY8GUIE_U5eSyI,16153
10
+ ibm_cloud_sdk_core/version.py,sha256=CZH4AvE3hZ2zkLpUhmHYIbDnNIcTO-hBAWoV-nc3O4c,23
11
+ ibm_cloud_sdk_core/authenticators/__init__.py,sha256=kfO8cLILf8zmNM_Uth652jZHEUUkTqEcwvTzDK7WCOw,2622
12
+ ibm_cloud_sdk_core/authenticators/authenticator.py,sha256=q-4pswHnL37_TAVYd_3G6zPezKSeuncKLarL1fWITxc,2048
13
13
  ibm_cloud_sdk_core/authenticators/basic_authenticator.py,sha256=-VETJqCwAj77_RNhokAp8rLqN0lkGj3TPF6xU1_lpY8,3366
14
14
  ibm_cloud_sdk_core/authenticators/bearer_token_authenticator.py,sha256=McSziK-DUj64TpFyzNps6XR2IjRvyzOR_8C7V1pIfwE,2861
15
15
  ibm_cloud_sdk_core/authenticators/container_authenticator.py,sha256=Ex0bH5sCZoIK30SGlwajE6o-LjuGWZPvqBozbm5QCd0,7053
@@ -18,6 +18,7 @@ ibm_cloud_sdk_core/authenticators/iam_assume_authenticator.py,sha256=MxMJnB6YvkB
18
18
  ibm_cloud_sdk_core/authenticators/iam_authenticator.py,sha256=ozrFBdVah1y8gcLL68fmReXCFEAltOGLCIuA6PuWLSY,4597
19
19
  ibm_cloud_sdk_core/authenticators/iam_request_based_authenticator.py,sha256=0k-rtfaYV3KXxNCEOq8njNDAC4KmUJSbVxOPjbhIxWc,4686
20
20
  ibm_cloud_sdk_core/authenticators/mcsp_authenticator.py,sha256=z3fFZf-iW0hsZ9qfJ1y-jKQ3DtNPGf9M9QNgu0gfMoA,5350
21
+ ibm_cloud_sdk_core/authenticators/mcspv2_authenticator.py,sha256=y_6FhZGly-C_vS4Up4wiQgfNesn5mz_hdc9jgfgltmA,11747
21
22
  ibm_cloud_sdk_core/authenticators/no_auth_authenticator.py,sha256=dzuU6IJC19SocVHy7Fyln6xrfGvlqnXGeUNR9llspYo,979
22
23
  ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py,sha256=48Cq9YRRRXmPjhHvnW8-uNgqP8NfNTAG_ajxwg1Mdw0,5414
23
24
  ibm_cloud_sdk_core/token_managers/__init__.py,sha256=NEiims6qB8doxq6wtlTBYCIdwf2wRiMTrV0bgfv7WAg,606
@@ -28,10 +29,11 @@ ibm_cloud_sdk_core/token_managers/iam_request_based_token_manager.py,sha256=DMFh
28
29
  ibm_cloud_sdk_core/token_managers/iam_token_manager.py,sha256=bG94h0Io6XaneLUcSuJzLlKSpFLdKH49TieRNAY7fvA,4358
29
30
  ibm_cloud_sdk_core/token_managers/jwt_token_manager.py,sha256=FDBdvirmUcJu5vIb5pdhqoQeFS6j0GBSDsF0HtLjg48,3785
30
31
  ibm_cloud_sdk_core/token_managers/mcsp_token_manager.py,sha256=jaVwmqPnWF0ZG3lGOL33Q8wXj2tOQX52VYvle5sE_zM,4244
32
+ ibm_cloud_sdk_core/token_managers/mcspv2_token_manager.py,sha256=JPzAwDpP7B5xWoe_M2QeykzqYT69_R8bR-F9DLzf-kw,8005
31
33
  ibm_cloud_sdk_core/token_managers/token_manager.py,sha256=7vSaSctmy46o5OVnmvVafBAGKzoNjA7kJEzd-rrcLWM,7993
32
34
  ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py,sha256=0oYXV-Y2o5L3_70r53CxtJLS6Y2pIkzbi1CW1z-QR4Y,7014
33
- ibm_cloud_sdk_core-3.23.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
34
- ibm_cloud_sdk_core-3.23.0.dist-info/METADATA,sha256=26yk5x4NgPIiJ1I5Tnc-wYDss1M3YjzJT2H5uWEXw8o,8652
35
- ibm_cloud_sdk_core-3.23.0.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
36
- ibm_cloud_sdk_core-3.23.0.dist-info/top_level.txt,sha256=otLtvxe-8ugPRmPqeSnbaOjnAl0qjDRZ1HSkC3aeLpI,19
37
- ibm_cloud_sdk_core-3.23.0.dist-info/RECORD,,
35
+ ibm_cloud_sdk_core-3.24.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
36
+ ibm_cloud_sdk_core-3.24.1.dist-info/METADATA,sha256=9B7etHBSD3El6-laJ7J_JvugFQz3ISkkuw_l_RwgqcI,8674
37
+ ibm_cloud_sdk_core-3.24.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ ibm_cloud_sdk_core-3.24.1.dist-info/top_level.txt,sha256=otLtvxe-8ugPRmPqeSnbaOjnAl0qjDRZ1HSkC3aeLpI,19
39
+ ibm_cloud_sdk_core-3.24.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5