ibm-cloud-sdk-core 3.15.0__py3-none-any.whl → 3.20.6__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.
- ibm_cloud_sdk_core/__init__.py +1 -0
- ibm_cloud_sdk_core/api_exception.py +18 -4
- ibm_cloud_sdk_core/authenticators/__init__.py +1 -0
- ibm_cloud_sdk_core/authenticators/authenticator.py +3 -3
- ibm_cloud_sdk_core/authenticators/basic_authenticator.py +5 -6
- ibm_cloud_sdk_core/authenticators/bearer_token_authenticator.py +1 -1
- ibm_cloud_sdk_core/authenticators/container_authenticator.py +25 -16
- ibm_cloud_sdk_core/authenticators/cp4d_authenticator.py +34 -20
- ibm_cloud_sdk_core/authenticators/iam_authenticator.py +22 -13
- ibm_cloud_sdk_core/authenticators/iam_request_based_authenticator.py +5 -7
- ibm_cloud_sdk_core/authenticators/mcsp_authenticator.py +130 -0
- ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py +7 -10
- ibm_cloud_sdk_core/base_service.py +113 -92
- ibm_cloud_sdk_core/detailed_response.py +21 -15
- ibm_cloud_sdk_core/get_authenticator.py +28 -16
- ibm_cloud_sdk_core/http_adapter.py +28 -0
- ibm_cloud_sdk_core/private_helpers.py +34 -0
- ibm_cloud_sdk_core/token_managers/container_token_manager.py +61 -30
- ibm_cloud_sdk_core/token_managers/cp4d_token_manager.py +34 -21
- ibm_cloud_sdk_core/token_managers/iam_request_based_token_manager.py +43 -20
- ibm_cloud_sdk_core/token_managers/iam_token_manager.py +24 -13
- ibm_cloud_sdk_core/token_managers/jwt_token_manager.py +3 -16
- ibm_cloud_sdk_core/token_managers/mcsp_token_manager.py +102 -0
- ibm_cloud_sdk_core/token_managers/token_manager.py +13 -23
- ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py +33 -13
- ibm_cloud_sdk_core/utils.py +126 -32
- ibm_cloud_sdk_core/version.py +1 -1
- {ibm_cloud_sdk_core-3.15.0.dist-info → ibm_cloud_sdk_core-3.20.6.dist-info}/METADATA +39 -30
- ibm_cloud_sdk_core-3.20.6.dist-info/RECORD +34 -0
- {ibm_cloud_sdk_core-3.15.0.dist-info → ibm_cloud_sdk_core-3.20.6.dist-info}/WHEEL +1 -1
- ibm_cloud_sdk_core-3.20.6.dist-info/top_level.txt +1 -0
- ibm_cloud_sdk_core-3.15.0.dist-info/RECORD +0 -52
- ibm_cloud_sdk_core-3.15.0.dist-info/top_level.txt +0 -3
- ibm_cloud_sdk_core-3.15.0.dist-info/zip-safe +0 -1
- test/__init__.py +0 -0
- test/test_api_exception.py +0 -73
- test/test_authenticator.py +0 -21
- test/test_base_service.py +0 -925
- test/test_basic_authenticator.py +0 -36
- test/test_bearer_authenticator.py +0 -28
- test/test_container_authenticator.py +0 -105
- test/test_container_token_manager.py +0 -283
- test/test_cp4d_authenticator.py +0 -171
- test/test_cp4d_token_manager.py +0 -56
- test/test_detailed_response.py +0 -57
- test/test_iam_authenticator.py +0 -157
- test/test_iam_token_manager.py +0 -362
- test/test_jwt_token_manager.py +0 -109
- test/test_no_auth_authenticator.py +0 -15
- test/test_token_manager.py +0 -84
- test/test_utils.py +0 -634
- test/test_vpc_instance_authenticator.py +0 -66
- test/test_vpc_instance_token_manager.py +0 -266
- test_integration/__init__.py +0 -0
- test_integration/test_cp4d_authenticator_integration.py +0 -45
- {ibm_cloud_sdk_core-3.15.0.dist-info → ibm_cloud_sdk_core-3.20.6.dist-info}/LICENSE +0 -0
test/test_basic_authenticator.py
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# pylint: disable=missing-docstring
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
|
-
from ibm_cloud_sdk_core.authenticators import BasicAuthenticator, Authenticator
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_basic_authenticator():
|
|
8
|
-
authenticator = BasicAuthenticator('my_username', 'my_password')
|
|
9
|
-
assert authenticator is not None
|
|
10
|
-
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_BASIC
|
|
11
|
-
assert authenticator.username == 'my_username'
|
|
12
|
-
assert authenticator.password == 'my_password'
|
|
13
|
-
|
|
14
|
-
request = {'headers': {}}
|
|
15
|
-
authenticator.authenticate(request)
|
|
16
|
-
assert request['headers']['Authorization'] == 'Basic bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ='
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_basic_authenticator_validate_failed():
|
|
20
|
-
with pytest.raises(ValueError) as err:
|
|
21
|
-
BasicAuthenticator('my_username', None)
|
|
22
|
-
assert str(err.value) == 'The username and password shouldn\'t be None.'
|
|
23
|
-
|
|
24
|
-
with pytest.raises(ValueError) as err:
|
|
25
|
-
BasicAuthenticator(None, 'my_password')
|
|
26
|
-
assert str(err.value) == 'The username and password shouldn\'t be None.'
|
|
27
|
-
|
|
28
|
-
with pytest.raises(ValueError) as err:
|
|
29
|
-
BasicAuthenticator('{my_username}', 'my_password')
|
|
30
|
-
assert str(err.value) == 'The username and password shouldn\'t start or end with curly brackets or quotes. '\
|
|
31
|
-
'Please remove any surrounding {, }, or \" characters.'
|
|
32
|
-
|
|
33
|
-
with pytest.raises(ValueError) as err:
|
|
34
|
-
BasicAuthenticator('my_username', '{my_password}')
|
|
35
|
-
assert str(err.value) == 'The username and password shouldn\'t start or end with curly brackets or quotes. '\
|
|
36
|
-
'Please remove any surrounding {, }, or \" characters.'
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# pylint: disable=missing-docstring
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
|
-
from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, Authenticator
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_bearer_authenticator():
|
|
8
|
-
authenticator = BearerTokenAuthenticator('my_bearer_token')
|
|
9
|
-
assert authenticator is not None
|
|
10
|
-
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_BEARERTOKEN
|
|
11
|
-
assert authenticator.bearer_token == 'my_bearer_token'
|
|
12
|
-
|
|
13
|
-
authenticator.set_bearer_token('james bond')
|
|
14
|
-
assert authenticator.bearer_token == 'james bond'
|
|
15
|
-
|
|
16
|
-
request = {'headers': {}}
|
|
17
|
-
authenticator.authenticate(request)
|
|
18
|
-
assert request['headers']['Authorization'] == 'Bearer james bond'
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def test_bearer_validate_failed():
|
|
22
|
-
with pytest.raises(ValueError) as err:
|
|
23
|
-
BearerTokenAuthenticator(None)
|
|
24
|
-
assert str(err.value) == 'The bearer token shouldn\'t be None.'
|
|
25
|
-
authenticator = BearerTokenAuthenticator('my_bearer_token')
|
|
26
|
-
with pytest.raises(ValueError) as err:
|
|
27
|
-
authenticator.set_bearer_token(None)
|
|
28
|
-
assert str(err.value) == 'The bearer token shouldn\'t be None.'
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# pylint: disable=missing-docstring
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
|
-
from ibm_cloud_sdk_core.authenticators import ContainerAuthenticator, Authenticator
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_container_authenticator():
|
|
8
|
-
authenticator = ContainerAuthenticator(iam_profile_name='iam-user-123')
|
|
9
|
-
assert authenticator is not None
|
|
10
|
-
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_CONTAINER
|
|
11
|
-
assert authenticator.token_manager.cr_token_filename is None
|
|
12
|
-
assert authenticator.token_manager.iam_profile_name == 'iam-user-123'
|
|
13
|
-
assert authenticator.token_manager.iam_profile_id is None
|
|
14
|
-
assert authenticator.token_manager.client_id is None
|
|
15
|
-
assert authenticator.token_manager.client_secret is None
|
|
16
|
-
assert authenticator.token_manager.disable_ssl_verification is False
|
|
17
|
-
assert authenticator.token_manager.headers is None
|
|
18
|
-
assert authenticator.token_manager.proxies is None
|
|
19
|
-
assert authenticator.token_manager.scope is None
|
|
20
|
-
|
|
21
|
-
authenticator.set_cr_token_filename('path/to/token')
|
|
22
|
-
assert authenticator.token_manager.cr_token_filename == 'path/to/token'
|
|
23
|
-
|
|
24
|
-
# Set the IAM profile to None to trigger a validation which will fail,
|
|
25
|
-
# because both of the profile and ID are None.
|
|
26
|
-
with pytest.raises(ValueError) as err:
|
|
27
|
-
authenticator.set_iam_profile_name(None)
|
|
28
|
-
assert str(
|
|
29
|
-
err.value) == 'At least one of iam_profile_name or iam_profile_id must be specified.'
|
|
30
|
-
|
|
31
|
-
authenticator.set_iam_profile_id('iam-id-123')
|
|
32
|
-
assert authenticator.token_manager.iam_profile_id == 'iam-id-123'
|
|
33
|
-
|
|
34
|
-
authenticator.set_iam_profile_name('iam-user-123')
|
|
35
|
-
assert authenticator.token_manager.iam_profile_name == 'iam-user-123'
|
|
36
|
-
|
|
37
|
-
authenticator.set_client_id_and_secret('tom', 'jerry')
|
|
38
|
-
assert authenticator.token_manager.client_id == 'tom'
|
|
39
|
-
assert authenticator.token_manager.client_secret == 'jerry'
|
|
40
|
-
|
|
41
|
-
authenticator.set_scope('scope1 scope2 scope3')
|
|
42
|
-
assert authenticator.token_manager.scope == 'scope1 scope2 scope3'
|
|
43
|
-
|
|
44
|
-
with pytest.raises(TypeError) as err:
|
|
45
|
-
authenticator.set_headers('dummy')
|
|
46
|
-
assert str(err.value) == 'headers must be a dictionary'
|
|
47
|
-
|
|
48
|
-
authenticator.set_headers({'dummy': 'headers'})
|
|
49
|
-
assert authenticator.token_manager.headers == {'dummy': 'headers'}
|
|
50
|
-
|
|
51
|
-
with pytest.raises(TypeError) as err:
|
|
52
|
-
authenticator.set_proxies('dummy')
|
|
53
|
-
assert str(err.value) == 'proxies must be a dictionary'
|
|
54
|
-
|
|
55
|
-
authenticator.set_proxies({'dummy': 'proxies'})
|
|
56
|
-
assert authenticator.token_manager.proxies == {'dummy': 'proxies'}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def test_disable_ssl_verification():
|
|
60
|
-
authenticator = ContainerAuthenticator(
|
|
61
|
-
iam_profile_name='iam-user-123', disable_ssl_verification=True)
|
|
62
|
-
assert authenticator.token_manager.disable_ssl_verification is True
|
|
63
|
-
|
|
64
|
-
authenticator.set_disable_ssl_verification(False)
|
|
65
|
-
assert authenticator.token_manager.disable_ssl_verification is False
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def test_invalid_disable_ssl_verification_type():
|
|
69
|
-
with pytest.raises(TypeError) as err:
|
|
70
|
-
authenticator = ContainerAuthenticator(
|
|
71
|
-
iam_profile_name='iam-user-123', disable_ssl_verification='True')
|
|
72
|
-
assert str(err.value) == 'disable_ssl_verification must be a bool'
|
|
73
|
-
|
|
74
|
-
authenticator = ContainerAuthenticator(iam_profile_name='iam-user-123')
|
|
75
|
-
assert authenticator.token_manager.disable_ssl_verification is False
|
|
76
|
-
|
|
77
|
-
with pytest.raises(TypeError) as err:
|
|
78
|
-
authenticator.set_disable_ssl_verification('True')
|
|
79
|
-
assert str(err.value) == 'status must be a bool'
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def test_container_authenticator_with_scope():
|
|
83
|
-
authenticator = ContainerAuthenticator(
|
|
84
|
-
iam_profile_name='iam-user-123', scope='scope1 scope2')
|
|
85
|
-
assert authenticator is not None
|
|
86
|
-
assert authenticator.token_manager.scope == 'scope1 scope2'
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def test_authenticator_validate_failed():
|
|
90
|
-
with pytest.raises(ValueError) as err:
|
|
91
|
-
ContainerAuthenticator(None)
|
|
92
|
-
assert str(
|
|
93
|
-
err.value) == 'At least one of iam_profile_name or iam_profile_id must be specified.'
|
|
94
|
-
|
|
95
|
-
with pytest.raises(ValueError) as err:
|
|
96
|
-
ContainerAuthenticator(
|
|
97
|
-
iam_profile_name='iam-user-123', client_id='my_client_id')
|
|
98
|
-
assert str(
|
|
99
|
-
err.value) == 'Both client_id and client_secret should be initialized.'
|
|
100
|
-
|
|
101
|
-
with pytest.raises(ValueError) as err:
|
|
102
|
-
ContainerAuthenticator(
|
|
103
|
-
iam_profile_name='iam-user-123', client_secret='my_client_secret')
|
|
104
|
-
assert str(
|
|
105
|
-
err.value) == 'Both client_id and client_secret should be initialized.'
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
# pylint: disable=missing-docstring
|
|
2
|
-
import json
|
|
3
|
-
import os
|
|
4
|
-
import time
|
|
5
|
-
from urllib.parse import parse_qs
|
|
6
|
-
|
|
7
|
-
import responses
|
|
8
|
-
import pytest
|
|
9
|
-
|
|
10
|
-
from ibm_cloud_sdk_core import ApiException, ContainerTokenManager
|
|
11
|
-
from ibm_cloud_sdk_core.authenticators import ContainerAuthenticator
|
|
12
|
-
|
|
13
|
-
# pylint: disable=line-too-long
|
|
14
|
-
TEST_ACCESS_TOKEN_1 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImhlbGxvIiwicm9sZSI6InVzZXIiLCJwZXJtaXNzaW9ucyI6WyJhZG1pbmlzdHJhdG9yIiwiZGVwbG95bWVudF9hZG1pbiJdLCJzdWIiOiJoZWxsbyIsImlzcyI6IkpvaG4iLCJhdWQiOiJEU1giLCJ1aWQiOiI5OTkiLCJpYXQiOjE1NjAyNzcwNTEsImV4cCI6MTU2MDI4MTgxOSwianRpIjoiMDRkMjBiMjUtZWUyZC00MDBmLTg2MjMtOGNkODA3MGI1NDY4In0.cIodB4I6CCcX8vfIImz7Cytux3GpWyObt9Gkur5g1QI'
|
|
15
|
-
TEST_ACCESS_TOKEN_2 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjIzMDQ5ODE1MWMyMTRiNzg4ZGQ5N2YyMmI4NTQxMGE1In0.eyJ1c2VybmFtZSI6ImR1bW15Iiwicm9sZSI6IkFkbWluIiwicGVybWlzc2lvbnMiOlsiYWRtaW5pc3RyYXRvciIsIm1hbmFnZV9jYXRhbG9nIl0sInN1YiI6ImFkbWluIiwiaXNzIjoic3NzIiwiYXVkIjoic3NzIiwidWlkIjoic3NzIiwiaWF0IjozNjAwLCJleHAiOjE2MjgwMDcwODF9.zvUDpgqWIWs7S1CuKv40ERw1IZ5FqSFqQXsrwZJyfRM'
|
|
16
|
-
TEST_REFRESH_TOKEN = 'Xj7Gle500MachEOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImhlbGxvIiwicm9sZSI6InVzZXIiLCJwZXJtaXNzaW9ucyI6WyJhZG1pbmlzdHJhdG9yIiwiZGVwbG95bWVudF9hZG1pbiJdLCJzdWIiOiJoZWxsbyIsImlzcyI6IkpvaG4iLCJhdWQiOiJEU1giLCJ1aWQiOiI5OTkiLCJpYXQiOjE1NjAyNzcwNTEsImV4cCI6MTU2MDI4MTgxOSwianRpIjoiMDRkMjBiMjUtZWUyZC00MDBmLTg2MjMtOGNkODA3MGI1NDY4In0.cIodB4I6CCcX8vfIImz7Cytux3GpWyObt9Gkur5g1QI'
|
|
17
|
-
MOCK_IAM_PROFILE_NAME = 'iam-user-123'
|
|
18
|
-
MOCK_CLIENT_ID = 'client-id-1'
|
|
19
|
-
MOCK_CLIENT_SECRET = 'client-secret-1'
|
|
20
|
-
|
|
21
|
-
cr_token_file = os.path.join(os.path.dirname(__file__), '../resources/cr-token.txt')
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _get_current_time() -> int:
|
|
25
|
-
return int(time.time())
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def mock_iam_response(func):
|
|
29
|
-
"""This is decorator function which extends `responses.activate`.
|
|
30
|
-
This sets up all the mock response stuffs.
|
|
31
|
-
"""
|
|
32
|
-
def callback(request):
|
|
33
|
-
assert request.headers['Accept'] == 'application/json'
|
|
34
|
-
assert request.headers['Content-Type'] == 'application/x-www-form-urlencoded'
|
|
35
|
-
|
|
36
|
-
payload = parse_qs(request.body)
|
|
37
|
-
|
|
38
|
-
assert payload['cr_token'][0] == 'cr-token-1'
|
|
39
|
-
assert payload['grant_type'][0] == 'urn:ibm:params:oauth:grant-type:cr-token'
|
|
40
|
-
assert payload.get('profile_name', [None])[0] or payload.get('profile_id', [None])[0]
|
|
41
|
-
|
|
42
|
-
status_code = 200
|
|
43
|
-
|
|
44
|
-
scope = payload.get('scope')[0] if payload.get('scope') else None
|
|
45
|
-
if scope == 'send-second-token':
|
|
46
|
-
access_token = TEST_ACCESS_TOKEN_2
|
|
47
|
-
elif scope == 'status-bad-request':
|
|
48
|
-
access_token = None
|
|
49
|
-
status_code = 400
|
|
50
|
-
elif scope == 'check-basic-auth':
|
|
51
|
-
assert request.headers['Authorization'] == 'Basic Y2xpZW50LWlkLTE6Y2xpZW50LXNlY3JldC0x'
|
|
52
|
-
access_token = TEST_ACCESS_TOKEN_1
|
|
53
|
-
else:
|
|
54
|
-
access_token = TEST_ACCESS_TOKEN_1
|
|
55
|
-
|
|
56
|
-
response = json.dumps({
|
|
57
|
-
'access_token': access_token,
|
|
58
|
-
'token_type': 'Bearer',
|
|
59
|
-
'expires_in': 3600,
|
|
60
|
-
'expiration': _get_current_time()+3600,
|
|
61
|
-
'refresh_token': TEST_REFRESH_TOKEN,
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
return (status_code, {}, response)
|
|
65
|
-
|
|
66
|
-
@responses.activate
|
|
67
|
-
def wrapper():
|
|
68
|
-
response = responses.CallbackResponse(
|
|
69
|
-
method=responses.POST,
|
|
70
|
-
url='https://iam.cloud.ibm.com/identity/token',
|
|
71
|
-
callback=callback,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
responses.add(response)
|
|
75
|
-
|
|
76
|
-
func()
|
|
77
|
-
|
|
78
|
-
return wrapper
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@mock_iam_response
|
|
82
|
-
def test_request_token_auth_default():
|
|
83
|
-
iam_url = "https://iam.cloud.ibm.com/identity/token"
|
|
84
|
-
|
|
85
|
-
token_manager = ContainerTokenManager(
|
|
86
|
-
cr_token_filename=cr_token_file,
|
|
87
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
88
|
-
)
|
|
89
|
-
token_manager.request_token()
|
|
90
|
-
|
|
91
|
-
assert len(responses.calls) == 1
|
|
92
|
-
assert responses.calls[0].request.url == iam_url
|
|
93
|
-
assert responses.calls[0].request.headers.get('Authorization') is None
|
|
94
|
-
assert json.loads(responses.calls[0].response.text)['access_token'] == TEST_ACCESS_TOKEN_1
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@mock_iam_response
|
|
98
|
-
def test_request_token_auth_in_ctor():
|
|
99
|
-
default_auth_header = 'Basic Yng6Yng='
|
|
100
|
-
token_manager = ContainerTokenManager(
|
|
101
|
-
cr_token_filename=cr_token_file,
|
|
102
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
103
|
-
client_id='foo',
|
|
104
|
-
client_secret='bar')
|
|
105
|
-
|
|
106
|
-
token_manager.request_token()
|
|
107
|
-
|
|
108
|
-
assert len(responses.calls) == 1
|
|
109
|
-
assert responses.calls[0].request.headers['Authorization'] != default_auth_header
|
|
110
|
-
assert json.loads(responses.calls[0].response.text)['access_token'] == TEST_ACCESS_TOKEN_1
|
|
111
|
-
assert 'scope' not in responses.calls[0].response.request.body
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
@mock_iam_response
|
|
115
|
-
def test_request_token_auth_in_ctor_with_scope():
|
|
116
|
-
default_auth_header = 'Basic Yng6Yng='
|
|
117
|
-
token_manager = ContainerTokenManager(
|
|
118
|
-
cr_token_filename=cr_token_file,
|
|
119
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
120
|
-
client_id='foo',
|
|
121
|
-
client_secret='bar',
|
|
122
|
-
scope='john snow')
|
|
123
|
-
|
|
124
|
-
token_manager.request_token()
|
|
125
|
-
|
|
126
|
-
assert len(responses.calls) == 1
|
|
127
|
-
assert responses.calls[0].request.headers['Authorization'] != default_auth_header
|
|
128
|
-
assert json.loads(responses.calls[0].response.text)['access_token'] == TEST_ACCESS_TOKEN_1
|
|
129
|
-
assert 'scope=john+snow' in responses.calls[0].response.request.body
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def test_retrieve_cr_token_success():
|
|
133
|
-
token_manager = ContainerTokenManager(
|
|
134
|
-
cr_token_filename=cr_token_file,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
cr_token = token_manager.retrieve_cr_token()
|
|
138
|
-
|
|
139
|
-
assert cr_token == 'cr-token-1'
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def test_retrieve_cr_token_fail():
|
|
143
|
-
token_manager = ContainerTokenManager(
|
|
144
|
-
cr_token_filename='bogus-cr-token-file',
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
with pytest.raises(Exception) as err:
|
|
148
|
-
token_manager.retrieve_cr_token()
|
|
149
|
-
|
|
150
|
-
assert str(err.value) == 'Unable to retrieve the CR token value from file bogus-cr-token-file: [Errno 2] No such file or directory: \'bogus-cr-token-file\''
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
@mock_iam_response
|
|
154
|
-
def test_get_token_success():
|
|
155
|
-
token_manager = ContainerTokenManager(
|
|
156
|
-
cr_token_filename=cr_token_file,
|
|
157
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
access_token = token_manager.access_token
|
|
161
|
-
assert access_token is None
|
|
162
|
-
|
|
163
|
-
access_token = token_manager.get_token()
|
|
164
|
-
assert access_token == TEST_ACCESS_TOKEN_1
|
|
165
|
-
assert token_manager.access_token == TEST_ACCESS_TOKEN_1
|
|
166
|
-
|
|
167
|
-
# Verify the token manager return the cached value.
|
|
168
|
-
# Before we call the `get_token` again, set the expiration and time.
|
|
169
|
-
# This is necessary because we are using a fix JWT response.
|
|
170
|
-
token_manager.expire_time = _get_current_time() + 3600
|
|
171
|
-
token_manager.refresh_time = _get_current_time() + 3600
|
|
172
|
-
token_manager.set_scope('send-second-token')
|
|
173
|
-
access_token = token_manager.get_token()
|
|
174
|
-
assert access_token == TEST_ACCESS_TOKEN_1
|
|
175
|
-
assert token_manager.access_token == TEST_ACCESS_TOKEN_1
|
|
176
|
-
|
|
177
|
-
# Force expiration to get the second token.
|
|
178
|
-
token_manager.expire_time = _get_current_time() - 1
|
|
179
|
-
access_token = token_manager.get_token()
|
|
180
|
-
assert access_token == TEST_ACCESS_TOKEN_2
|
|
181
|
-
assert token_manager.access_token == TEST_ACCESS_TOKEN_2
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
@mock_iam_response
|
|
185
|
-
def test_request_token_success():
|
|
186
|
-
token_manager = ContainerTokenManager(
|
|
187
|
-
cr_token_filename=cr_token_file,
|
|
188
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
token_response = token_manager.request_token()
|
|
192
|
-
assert token_response['access_token'] == TEST_ACCESS_TOKEN_1
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
@mock_iam_response
|
|
196
|
-
def test_authenticate_success():
|
|
197
|
-
authenticator = ContainerAuthenticator(
|
|
198
|
-
cr_token_filename=cr_token_file,
|
|
199
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME)
|
|
200
|
-
|
|
201
|
-
request = {'headers': {}}
|
|
202
|
-
|
|
203
|
-
authenticator.authenticate(request)
|
|
204
|
-
assert request['headers']['Authorization'] == 'Bearer ' + TEST_ACCESS_TOKEN_1
|
|
205
|
-
|
|
206
|
-
# Verify the token manager return the cached value.
|
|
207
|
-
# Before we call the `get_token` again, set the expiration and time.
|
|
208
|
-
# This is necessary because we are using a fix JWT response.
|
|
209
|
-
authenticator.token_manager.expire_time = _get_current_time() + 3600
|
|
210
|
-
authenticator.token_manager.refresh_time = _get_current_time() + 3600
|
|
211
|
-
authenticator.token_manager.set_scope('send-second-token')
|
|
212
|
-
authenticator.authenticate(request)
|
|
213
|
-
assert request['headers']['Authorization'] == 'Bearer ' + TEST_ACCESS_TOKEN_1
|
|
214
|
-
|
|
215
|
-
# Force expiration to get the second token.
|
|
216
|
-
authenticator.token_manager.expire_time = _get_current_time() - 1
|
|
217
|
-
authenticator.authenticate(request)
|
|
218
|
-
assert request['headers']['Authorization'] == 'Bearer ' + TEST_ACCESS_TOKEN_2
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
@mock_iam_response
|
|
222
|
-
def test_authenticate_fail_no_cr_token():
|
|
223
|
-
authenticator = ContainerAuthenticator(
|
|
224
|
-
cr_token_filename='bogus-cr-token-file',
|
|
225
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
226
|
-
url='https://bogus.iam.endpoint')
|
|
227
|
-
|
|
228
|
-
request = {'headers': {}}
|
|
229
|
-
|
|
230
|
-
with pytest.raises(Exception) as err:
|
|
231
|
-
authenticator.authenticate(request)
|
|
232
|
-
|
|
233
|
-
assert str(err.value) == 'Unable to retrieve the CR token value from file bogus-cr-token-file: [Errno 2] No such file or directory: \'bogus-cr-token-file\''
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
@mock_iam_response
|
|
237
|
-
def test_authenticate_fail_iam():
|
|
238
|
-
authenticator = ContainerAuthenticator(
|
|
239
|
-
cr_token_filename=cr_token_file,
|
|
240
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
241
|
-
scope='status-bad-request')
|
|
242
|
-
|
|
243
|
-
request = {'headers': {}}
|
|
244
|
-
|
|
245
|
-
with pytest.raises(ApiException) as err:
|
|
246
|
-
authenticator.authenticate(request)
|
|
247
|
-
|
|
248
|
-
assert str(err.value) == 'Error: Bad Request, Code: 400'
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
@mock_iam_response
|
|
252
|
-
def test_client_id_and_secret():
|
|
253
|
-
token_manager = ContainerTokenManager(
|
|
254
|
-
cr_token_filename=cr_token_file,
|
|
255
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
token_manager.set_client_id_and_secret(MOCK_CLIENT_ID, MOCK_CLIENT_SECRET)
|
|
259
|
-
token_manager.set_scope('check-basic-auth')
|
|
260
|
-
access_token = token_manager.get_token()
|
|
261
|
-
assert access_token == TEST_ACCESS_TOKEN_1
|
|
262
|
-
|
|
263
|
-
@mock_iam_response
|
|
264
|
-
def test_setter_methods():
|
|
265
|
-
token_manager = ContainerTokenManager(
|
|
266
|
-
cr_token_filename='bogus-cr-token-file',
|
|
267
|
-
iam_profile_name=MOCK_IAM_PROFILE_NAME,
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
assert token_manager.iam_profile_id is None
|
|
271
|
-
assert token_manager.iam_profile_name == MOCK_IAM_PROFILE_NAME
|
|
272
|
-
assert token_manager.cr_token_filename == 'bogus-cr-token-file'
|
|
273
|
-
|
|
274
|
-
token_manager.set_iam_profile_id('iam-id-123')
|
|
275
|
-
token_manager.set_iam_profile_name(None)
|
|
276
|
-
token_manager.set_cr_token_filename(cr_token_file)
|
|
277
|
-
|
|
278
|
-
assert token_manager.iam_profile_id == 'iam-id-123'
|
|
279
|
-
assert token_manager.iam_profile_name is None
|
|
280
|
-
assert token_manager.cr_token_filename == cr_token_file
|
|
281
|
-
|
|
282
|
-
access_token = token_manager.get_token()
|
|
283
|
-
assert access_token == TEST_ACCESS_TOKEN_1
|
test/test_cp4d_authenticator.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# pylint: disable=missing-docstring
|
|
2
|
-
import json
|
|
3
|
-
|
|
4
|
-
import jwt
|
|
5
|
-
import pytest
|
|
6
|
-
import responses
|
|
7
|
-
|
|
8
|
-
from ibm_cloud_sdk_core.authenticators import CloudPakForDataAuthenticator, Authenticator
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def test_cp4d_authenticator():
|
|
12
|
-
authenticator = CloudPakForDataAuthenticator(
|
|
13
|
-
'my_username', 'my_password', 'http://my_url')
|
|
14
|
-
assert authenticator is not None
|
|
15
|
-
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_CP4D
|
|
16
|
-
assert authenticator.token_manager.url == 'http://my_url/v1/authorize'
|
|
17
|
-
assert authenticator.token_manager.username == 'my_username'
|
|
18
|
-
assert authenticator.token_manager.password == 'my_password'
|
|
19
|
-
assert authenticator.token_manager.disable_ssl_verification is False
|
|
20
|
-
assert authenticator.token_manager.headers == {
|
|
21
|
-
'Content-Type': 'application/json'}
|
|
22
|
-
assert authenticator.token_manager.proxies is None
|
|
23
|
-
|
|
24
|
-
authenticator.set_disable_ssl_verification(True)
|
|
25
|
-
assert authenticator.token_manager.disable_ssl_verification is True
|
|
26
|
-
|
|
27
|
-
with pytest.raises(TypeError) as err:
|
|
28
|
-
authenticator.set_headers('dummy')
|
|
29
|
-
assert str(err.value) == 'headers must be a dictionary'
|
|
30
|
-
|
|
31
|
-
authenticator.set_headers({'dummy': 'headers'})
|
|
32
|
-
assert authenticator.token_manager.headers == {'dummy': 'headers'}
|
|
33
|
-
|
|
34
|
-
with pytest.raises(TypeError) as err:
|
|
35
|
-
authenticator.set_proxies('dummy')
|
|
36
|
-
assert str(err.value) == 'proxies must be a dictionary'
|
|
37
|
-
|
|
38
|
-
authenticator.set_proxies({'dummy': 'proxies'})
|
|
39
|
-
assert authenticator.token_manager.proxies == {'dummy': 'proxies'}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test_disable_ssl_verification():
|
|
43
|
-
authenticator = CloudPakForDataAuthenticator(
|
|
44
|
-
'my_username', 'my_password', 'http://my_url', disable_ssl_verification=True)
|
|
45
|
-
assert authenticator.token_manager.disable_ssl_verification is True
|
|
46
|
-
|
|
47
|
-
authenticator.set_disable_ssl_verification(False)
|
|
48
|
-
assert authenticator.token_manager.disable_ssl_verification is False
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def test_invalid_disable_ssl_verification_type():
|
|
52
|
-
with pytest.raises(TypeError) as err:
|
|
53
|
-
authenticator = CloudPakForDataAuthenticator(
|
|
54
|
-
'my_username', 'my_password', 'http://my_url', disable_ssl_verification='True')
|
|
55
|
-
assert str(err.value) == 'disable_ssl_verification must be a bool'
|
|
56
|
-
|
|
57
|
-
authenticator = CloudPakForDataAuthenticator(
|
|
58
|
-
'my_username', 'my_password', 'http://my_url')
|
|
59
|
-
assert authenticator.token_manager.disable_ssl_verification is False
|
|
60
|
-
|
|
61
|
-
with pytest.raises(TypeError) as err:
|
|
62
|
-
authenticator.set_disable_ssl_verification('True')
|
|
63
|
-
assert str(err.value) == 'status must be a bool'
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_cp4d_authenticator_validate_failed():
|
|
67
|
-
with pytest.raises(ValueError) as err:
|
|
68
|
-
CloudPakForDataAuthenticator('my_username', None, 'my_url')
|
|
69
|
-
assert str(
|
|
70
|
-
err.value) == 'Exactly one of `apikey` or `password` must be specified.'
|
|
71
|
-
|
|
72
|
-
with pytest.raises(ValueError) as err:
|
|
73
|
-
CloudPakForDataAuthenticator(username='my_username', url='my_url')
|
|
74
|
-
assert str(
|
|
75
|
-
err.value) == 'Exactly one of `apikey` or `password` must be specified.'
|
|
76
|
-
|
|
77
|
-
with pytest.raises(ValueError) as err:
|
|
78
|
-
CloudPakForDataAuthenticator(
|
|
79
|
-
'my_username', None, 'my_url', apikey=None)
|
|
80
|
-
assert str(
|
|
81
|
-
err.value) == 'Exactly one of `apikey` or `password` must be specified.'
|
|
82
|
-
|
|
83
|
-
with pytest.raises(ValueError) as err:
|
|
84
|
-
CloudPakForDataAuthenticator(None, 'my_password', 'my_url')
|
|
85
|
-
assert str(err.value) == 'The username shouldn\'t be None.'
|
|
86
|
-
|
|
87
|
-
with pytest.raises(ValueError) as err:
|
|
88
|
-
CloudPakForDataAuthenticator(password='my_password', url='my_url')
|
|
89
|
-
assert str(err.value) == 'The username shouldn\'t be None.'
|
|
90
|
-
|
|
91
|
-
with pytest.raises(ValueError) as err:
|
|
92
|
-
CloudPakForDataAuthenticator('my_username', 'my_password', None)
|
|
93
|
-
assert str(err.value) == 'The url shouldn\'t be None.'
|
|
94
|
-
|
|
95
|
-
with pytest.raises(ValueError) as err:
|
|
96
|
-
CloudPakForDataAuthenticator(
|
|
97
|
-
username='my_username', password='my_password')
|
|
98
|
-
assert str(err.value) == 'The url shouldn\'t be None.'
|
|
99
|
-
|
|
100
|
-
with pytest.raises(ValueError) as err:
|
|
101
|
-
CloudPakForDataAuthenticator('{my_username}', 'my_password', 'my_url')
|
|
102
|
-
assert str(err.value) == 'The username and password shouldn\'t start or end with curly brackets or quotes. '\
|
|
103
|
-
'Please remove any surrounding {, }, or \" characters.'
|
|
104
|
-
|
|
105
|
-
with pytest.raises(ValueError) as err:
|
|
106
|
-
CloudPakForDataAuthenticator('my_username', '{my_password}', 'my_url')
|
|
107
|
-
assert str(err.value) == 'The username and password shouldn\'t start or end with curly brackets or quotes. '\
|
|
108
|
-
'Please remove any surrounding {, }, or \" characters.'
|
|
109
|
-
|
|
110
|
-
with pytest.raises(ValueError) as err:
|
|
111
|
-
CloudPakForDataAuthenticator('my_username', 'my_password', '{my_url}')
|
|
112
|
-
assert str(err.value) == 'The url shouldn\'t start or end with curly brackets or quotes. '\
|
|
113
|
-
'Please remove any surrounding {, }, or \" characters.'
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
@responses.activate
|
|
117
|
-
def test_get_token():
|
|
118
|
-
url = "https://test"
|
|
119
|
-
access_token_layout = {
|
|
120
|
-
"username": "dummy",
|
|
121
|
-
"role": "Admin",
|
|
122
|
-
"permissions": [
|
|
123
|
-
"administrator",
|
|
124
|
-
"manage_catalog"
|
|
125
|
-
],
|
|
126
|
-
"sub": "admin",
|
|
127
|
-
"iss": "sss",
|
|
128
|
-
"aud": "sss",
|
|
129
|
-
"uid": "sss",
|
|
130
|
-
"iat": 1559324664,
|
|
131
|
-
"exp": 1559324664
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
access_token = jwt.encode(access_token_layout,
|
|
135
|
-
'secret', algorithm='HS256',
|
|
136
|
-
headers={'kid': '230498151c214b788dd97f22b85410a5'})
|
|
137
|
-
response = {
|
|
138
|
-
"token": access_token,
|
|
139
|
-
"token_type": "Bearer",
|
|
140
|
-
"expires_in": 3600,
|
|
141
|
-
"expiration": 1524167011,
|
|
142
|
-
"refresh_token": "jy4gl91BQ"
|
|
143
|
-
}
|
|
144
|
-
responses.add(responses.POST, url + '/v1/authorize',
|
|
145
|
-
body=json.dumps(response), status=200)
|
|
146
|
-
|
|
147
|
-
auth_headers = {'Host': 'cp4d.cloud.ibm.com:443'}
|
|
148
|
-
authenticator = CloudPakForDataAuthenticator(
|
|
149
|
-
'my_username', 'my_password', url + '/v1/authorize',
|
|
150
|
-
headers=auth_headers)
|
|
151
|
-
|
|
152
|
-
# Simulate an SDK API request that needs to be authenticated.
|
|
153
|
-
request = {'headers': {}}
|
|
154
|
-
|
|
155
|
-
# Trigger the "get token" processing to obtain the access token and add to the "SDK request".
|
|
156
|
-
authenticator.authenticate(request)
|
|
157
|
-
|
|
158
|
-
# Verify that the "authenticate()" method added the Authorization header
|
|
159
|
-
assert request['headers']['Authorization'] is not None
|
|
160
|
-
|
|
161
|
-
# Verify that the "get token" call contained the Host header.
|
|
162
|
-
assert responses.calls[0].request.headers.get(
|
|
163
|
-
'Host') == 'cp4d.cloud.ibm.com:443'
|
|
164
|
-
|
|
165
|
-
# Ensure '/v1/authorize' is added to the url if omitted
|
|
166
|
-
authenticator = CloudPakForDataAuthenticator(
|
|
167
|
-
'my_username', 'my_password', url)
|
|
168
|
-
|
|
169
|
-
request = {'headers': {}}
|
|
170
|
-
authenticator.authenticate(request)
|
|
171
|
-
assert request['headers']['Authorization'] is not None
|
test/test_cp4d_token_manager.py
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# pylint: disable=missing-docstring
|
|
2
|
-
import json
|
|
3
|
-
import time
|
|
4
|
-
|
|
5
|
-
import jwt
|
|
6
|
-
import responses
|
|
7
|
-
|
|
8
|
-
from ibm_cloud_sdk_core import CP4DTokenManager
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@responses.activate
|
|
12
|
-
def test_request_token():
|
|
13
|
-
url = "https://test"
|
|
14
|
-
now = time.time()
|
|
15
|
-
access_token_layout = {
|
|
16
|
-
"username": "dummy",
|
|
17
|
-
"role": "Admin",
|
|
18
|
-
"permissions": [
|
|
19
|
-
"administrator",
|
|
20
|
-
"manage_catalog"
|
|
21
|
-
],
|
|
22
|
-
"sub": "admin",
|
|
23
|
-
"iss": "sss",
|
|
24
|
-
"aud": "sss",
|
|
25
|
-
"uid": "sss",
|
|
26
|
-
"iat": now,
|
|
27
|
-
"exp": now + 3600
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
access_token = jwt.encode(access_token_layout,
|
|
31
|
-
'secret', algorithm='HS256',
|
|
32
|
-
headers={'kid': '230498151c214b788dd97f22b85410a5'})
|
|
33
|
-
response = {
|
|
34
|
-
"token": access_token,
|
|
35
|
-
}
|
|
36
|
-
responses.add(responses.POST, url + '/v1/authorize', body=json.dumps(response), status=200)
|
|
37
|
-
|
|
38
|
-
token_manager = CP4DTokenManager("username", "password", url)
|
|
39
|
-
token_manager.set_disable_ssl_verification(True)
|
|
40
|
-
token = token_manager.get_token()
|
|
41
|
-
|
|
42
|
-
assert len(responses.calls) == 1
|
|
43
|
-
assert responses.calls[0].request.url == url + '/v1/authorize'
|
|
44
|
-
assert token == access_token
|
|
45
|
-
|
|
46
|
-
token_manager = CP4DTokenManager("username", "password", url + '/v1/authorize')
|
|
47
|
-
token = token_manager.get_token()
|
|
48
|
-
assert len(responses.calls) == 2
|
|
49
|
-
assert responses.calls[1].request.url == url + '/v1/authorize'
|
|
50
|
-
assert token == access_token
|
|
51
|
-
|
|
52
|
-
token_manager = CP4DTokenManager(username="username", apikey="fake_api_key", url=url + '/v1/authorize')
|
|
53
|
-
token = token_manager.get_token()
|
|
54
|
-
assert len(responses.calls) == 3
|
|
55
|
-
assert responses.calls[2].request.url == url + '/v1/authorize'
|
|
56
|
-
assert token == access_token
|