Skip to content

Commit cbbcc1f

Browse files
committed
feat: add authentication_type method to authenticators
This commit adds a new method ('authentication_type()') to the Authenticator base class, and each authenticator implementation (subclasses of Authenticator). The function will return a string indicating the authenticator type ('basic', 'iam', etc.). This brings the python core in line with the Go, Java and Node cores.
1 parent 52ab020 commit cbbcc1f

15 files changed

+118
-50
lines changed

ibm_cloud_sdk_core/authenticators/authenticator.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@
1919

2020
class Authenticator(ABC):
2121
"""This interface defines the common methods and constants associated with an Authenticator implementation."""
22+
23+
# Constants representing the various authenticator types.
24+
AUTHTYPE_BASIC = 'basic'
25+
AUTHTYPE_BEARERTOKEN = 'bearerToken'
26+
AUTHTYPE_IAM = 'iam'
27+
AUTHTYPE_CONTAINER = 'container'
28+
AUTHTYPE_CP4D = 'cp4d'
29+
AUTHTYPE_NOAUTH = 'noAuth'
30+
AUTHTYPE_UNKNOWN = 'unknown'
31+
2232
@abstractmethod
2333
def authenticate(self, req: dict) -> None:
2434
"""Perform the necessary authentication steps for the specified request.
@@ -40,3 +50,8 @@ def validate(self) -> None:
4050
To be implemented by subclasses.
4151
"""
4252
pass
53+
54+
# pylint: disable=R0201
55+
def authentication_type(self) -> str:
56+
"""Returns the authenticator's type. This method should be overridden by each authenticator implementation."""
57+
return Authenticator.AUTHTYPE_UNKNOWN

ibm_cloud_sdk_core/authenticators/basic_authenticator.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,16 @@ class BasicAuthenticator(Authenticator):
3535
Raises:
3636
ValueError: The username or password is not specified or contains invalid characters.
3737
"""
38-
authentication_type = 'basic'
3938

4039
def __init__(self, username: str, password: str) -> None:
4140
self.username = username
4241
self.password = password
4342
self.validate()
4443
self.authorization_header = self.__construct_basic_auth_header()
4544

45+
def authentication_type(self) -> str:
46+
"""Returns this authenticator's type ('basic')."""
47+
return Authenticator.AUTHTYPE_BASIC
4648

4749
def validate(self) -> None:
4850
"""Validate username and password.
@@ -61,13 +63,12 @@ def validate(self) -> None:
6163
'The username and password shouldn\'t start or end with curly brackets or quotes. '
6264
'Please remove any surrounding {, }, or \" characters.')
6365

64-
6566
def __construct_basic_auth_header(self) -> str:
6667
authstring = "{0}:{1}".format(self.username, self.password)
67-
base64_authorization = base64.b64encode(authstring.encode('utf-8')).decode('utf-8')
68+
base64_authorization = base64.b64encode(
69+
authstring.encode('utf-8')).decode('utf-8')
6870
return 'Basic {0}'.format(base64_authorization)
6971

70-
7172
def authenticate(self, req: Request) -> None:
7273
"""Add basic authentication information to a request.
7374

ibm_cloud_sdk_core/authenticators/bearer_token_authenticator.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ class BearerTokenAuthenticator(Authenticator):
3333
Raises:
3434
ValueError: Bearer token is none.
3535
"""
36-
authentication_type = 'bearerToken'
3736

3837
def __init__(self, bearer_token: str) -> None:
3938
self.bearer_token = bearer_token
4039
self.validate()
4140

41+
def authentication_type(self) -> str:
42+
"""Returns this authenticator's type ('bearertoken')."""
43+
return Authenticator.AUTHTYPE_BEARERTOKEN
44+
4245
def validate(self) -> None:
4346
"""Validate the bearer token.
4447

ibm_cloud_sdk_core/authenticators/container_authenticator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from .iam_request_based_authenticator import IAMRequestBasedAuthenticator
2020
from ..token_managers.container_token_manager import ContainerTokenManager
21+
from .authenticator import Authenticator
2122

2223

2324
class ContainerAuthenticator(IAMRequestBasedAuthenticator):
@@ -62,7 +63,6 @@ class ContainerAuthenticator(IAMRequestBasedAuthenticator):
6263
ValueError: Neither of iam_profile_name or iam_profile_idk are set,
6364
or client_id, and/or client_secret are not valid for IAM token requests.
6465
"""
65-
authentication_type = 'container'
6666

6767
def __init__(self,
6868
cr_token_filename: Optional[str] = None,
@@ -86,6 +86,10 @@ def __init__(self,
8686

8787
self.validate()
8888

89+
def authentication_type(self) -> str:
90+
"""Returns this authenticator's type ('container')."""
91+
return Authenticator.AUTHTYPE_CONTAINER
92+
8993
def validate(self) -> None:
9094
"""Validates the iam_profile_name, iam_profile_id, client_id, and client_secret for IAM token requests.
9195

ibm_cloud_sdk_core/authenticators/cp4d_authenticator.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ class CloudPakForDataAuthenticator(Authenticator):
5050
TypeError: The `disable_ssl_verification` is not a bool.
5151
ValueError: The username, password/apikey, and/or url are not valid for CP4D token requests.
5252
"""
53-
authenticationdict = 'cp4d'
5453

5554
def __init__(self,
5655
username: str = None,
@@ -71,6 +70,10 @@ def __init__(self,
7170

7271
self.validate()
7372

73+
def authentication_type(self) -> str:
74+
"""Returns this authenticator's type ('cp4d')."""
75+
return Authenticator.AUTHTYPE_CP4D
76+
7477
def validate(self) -> None:
7578
"""Validate username, password, and url for token requests.
7679
@@ -85,7 +88,8 @@ def validate(self) -> None:
8588

8689
if ((self.token_manager.password is None and self.token_manager.apikey is None)
8790
or (self.token_manager.password is not None and self.token_manager.apikey is not None)):
88-
raise ValueError('Exactly one of `apikey` or `password` must be specified.')
91+
raise ValueError(
92+
'Exactly one of `apikey` or `password` must be specified.')
8993

9094
if self.token_manager.url is None:
9195
raise ValueError('The url shouldn\'t be None.')

ibm_cloud_sdk_core/authenticators/iam_authenticator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from typing import Dict, Optional
1818

19+
from .authenticator import Authenticator
1920
from .iam_request_based_authenticator import IAMRequestBasedAuthenticator
2021
from ..token_managers.iam_token_manager import IAMTokenManager
2122
from ..utils import has_bad_first_or_last_char
@@ -54,7 +55,6 @@ class IAMAuthenticator(IAMRequestBasedAuthenticator):
5455
TypeError: The `disable_ssl_verification` is not a bool.
5556
ValueError: The apikey, client_id, and/or client_secret are not valid for IAM token requests.
5657
"""
57-
authentication_type = 'iam'
5858

5959
def __init__(self,
6060
apikey: str,
@@ -77,6 +77,10 @@ def __init__(self,
7777

7878
self.validate()
7979

80+
def authentication_type(self) -> str:
81+
"""Returns this authenticator's type ('iam')."""
82+
return Authenticator.AUTHTYPE_IAM
83+
8084
def validate(self) -> None:
8185
"""Validates the apikey, client_id, and client_secret for IAM token requests.
8286

ibm_cloud_sdk_core/authenticators/no_auth_authenticator.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919

2020
class NoAuthAuthenticator(Authenticator):
2121
"""Performs no authentication."""
22-
authentication_type = 'noAuth'
22+
23+
def authentication_type(self) -> str:
24+
"""Returns this authenticator's type ('noauth')."""
25+
return Authenticator.AUTHTYPE_NOAUTH
2326

2427
def validate(self) -> None:
2528
pass

ibm_cloud_sdk_core/get_authenticator.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,28 @@ def get_authenticator_from_environment(service_name: str) -> Authenticator:
4343
def __construct_authenticator(config: dict) -> Authenticator:
4444
# Determine the authentication type if not specified explicitly.
4545
if config.get('AUTH_TYPE'):
46-
auth_type = config.get('AUTH_TYPE').lower()
46+
auth_type = config.get('AUTH_TYPE')
4747
elif config.get('AUTHTYPE'):
48-
auth_type = config.get('AUTHTYPE').lower()
48+
auth_type = config.get('AUTHTYPE')
4949
else:
50+
# If authtype wasn't specified explicitly, then determine the default.
5051
# If the APIKEY property is specified, then it should be IAM, otherwise Container Auth.
51-
auth_type = 'iam' if config.get('APIKEY') else 'container'
52+
if config.get('APIKEY'):
53+
auth_type = Authenticator.AUTHTYPE_IAM
54+
else:
55+
auth_type = Authenticator.AUTHTYPE_CONTAINER
5256

57+
auth_type = auth_type.lower()
5358
authenticator = None
5459

55-
if auth_type == 'basic':
60+
if auth_type == Authenticator.AUTHTYPE_BASIC.lower():
5661
authenticator = BasicAuthenticator(
5762
username=config.get('USERNAME'),
5863
password=config.get('PASSWORD'))
59-
elif auth_type == 'bearertoken':
64+
elif auth_type == Authenticator.AUTHTYPE_BEARERTOKEN.lower():
6065
authenticator = BearerTokenAuthenticator(
6166
bearer_token=config.get('BEARER_TOKEN'))
62-
elif auth_type == 'container':
67+
elif auth_type == Authenticator.AUTHTYPE_CONTAINER.lower():
6368
authenticator = ContainerAuthenticator(
6469
cr_token_filename=config.get('CR_TOKEN_FILENAME'),
6570
iam_profile_name=config.get('IAM_PROFILE_NAME'),
@@ -70,14 +75,14 @@ def __construct_authenticator(config: dict) -> Authenticator:
7075
disable_ssl_verification=config.get(
7176
'AUTH_DISABLE_SSL', 'false').lower() == 'true',
7277
scope=config.get('SCOPE'))
73-
elif auth_type == 'cp4d':
78+
elif auth_type == Authenticator.AUTHTYPE_CP4D.lower():
7479
authenticator = CloudPakForDataAuthenticator(
7580
username=config.get('USERNAME'),
7681
password=config.get('PASSWORD'),
7782
url=config.get('AUTH_URL'),
7883
apikey=config.get('APIKEY'),
7984
disable_ssl_verification=config.get('AUTH_DISABLE_SSL', 'false').lower() == 'true')
80-
elif auth_type == 'iam' and config.get('APIKEY'):
85+
elif auth_type == Authenticator.AUTHTYPE_IAM.lower() and config.get('APIKEY'):
8186
authenticator = IAMAuthenticator(
8287
apikey=config.get('APIKEY'),
8388
url=config.get('AUTH_URL'),
@@ -86,7 +91,7 @@ def __construct_authenticator(config: dict) -> Authenticator:
8691
disable_ssl_verification=config.get(
8792
'AUTH_DISABLE_SSL', 'false').lower() == 'true',
8893
scope=config.get('SCOPE'))
89-
elif auth_type == 'noauth':
94+
elif auth_type == Authenticator.AUTHTYPE_NOAUTH.lower():
9095
authenticator = NoAuthAuthenticator()
9196

9297
return authenticator

test/test_basic_authenticator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# pylint: disable=missing-docstring
22
import pytest
33

4-
from ibm_cloud_sdk_core.authenticators import BasicAuthenticator
4+
from ibm_cloud_sdk_core.authenticators import BasicAuthenticator, Authenticator
55

66

77
def test_basic_authenticator():
88
authenticator = BasicAuthenticator('my_username', 'my_password')
99
assert authenticator is not None
10+
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_BASIC
1011
assert authenticator.username == 'my_username'
1112
assert authenticator.password == 'my_password'
1213

test/test_bearer_authenticator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# pylint: disable=missing-docstring
22
import pytest
33

4-
from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator
4+
from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, Authenticator
55

66

77
def test_bearer_authenticator():
88
authenticator = BearerTokenAuthenticator('my_bearer_token')
99
assert authenticator is not None
10+
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_BEARERTOKEN
1011
assert authenticator.bearer_token == 'my_bearer_token'
1112

1213
authenticator.set_bearer_token('james bond')

test/test_container_authenticator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# pylint: disable=missing-docstring
22
import pytest
33

4-
from ibm_cloud_sdk_core.authenticators import ContainerAuthenticator
4+
from ibm_cloud_sdk_core.authenticators import ContainerAuthenticator, Authenticator
55

66

77
def test_container_authenticator():
88
authenticator = ContainerAuthenticator(iam_profile_name='iam-user-123')
99
assert authenticator is not None
10+
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_CONTAINER
1011
assert authenticator.token_manager.cr_token_filename is None
1112
assert authenticator.token_manager.iam_profile_name == 'iam-user-123'
1213
assert authenticator.token_manager.iam_profile_id is None

test/test_cp4d_authenticator.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
import pytest
66
import responses
77

8-
from ibm_cloud_sdk_core.authenticators import CloudPakForDataAuthenticator
8+
from ibm_cloud_sdk_core.authenticators import CloudPakForDataAuthenticator, Authenticator
99

1010

1111
def test_cp4d_authenticator():
1212
authenticator = CloudPakForDataAuthenticator(
1313
'my_username', 'my_password', 'http://my_url')
1414
assert authenticator is not None
15+
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_CP4D
1516
assert authenticator.token_manager.url == 'http://my_url/v1/authorize'
1617
assert authenticator.token_manager.username == 'my_username'
1718
assert authenticator.token_manager.password == 'my_password'
@@ -40,7 +41,7 @@ def test_cp4d_authenticator():
4041

4142
def test_disable_ssl_verification():
4243
authenticator = CloudPakForDataAuthenticator(
43-
'my_username', 'my_password', 'http://my_url', disable_ssl_verification=True)
44+
'my_username', 'my_password', 'http://my_url', disable_ssl_verification=True)
4445
assert authenticator.token_manager.disable_ssl_verification is True
4546

4647
authenticator.set_disable_ssl_verification(False)
@@ -54,7 +55,7 @@ def test_invalid_disable_ssl_verification_type():
5455
assert str(err.value) == 'disable_ssl_verification must be a bool'
5556

5657
authenticator = CloudPakForDataAuthenticator(
57-
'my_username', 'my_password', 'http://my_url')
58+
'my_username', 'my_password', 'http://my_url')
5859
assert authenticator.token_manager.disable_ssl_verification is False
5960

6061
with pytest.raises(TypeError) as err:

test/test_iam_authenticator.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
import pytest
66
import responses
77

8-
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
8+
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator, Authenticator
99

1010

1111
def test_iam_authenticator():
1212
authenticator = IAMAuthenticator(apikey='my_apikey')
1313
assert authenticator is not None
14+
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_IAM
1415
assert authenticator.token_manager.url == 'https://iam.cloud.ibm.com'
1516
assert authenticator.token_manager.client_id is None
1617
assert authenticator.token_manager.client_secret is None
@@ -46,7 +47,8 @@ def test_iam_authenticator():
4647

4748

4849
def test_disable_ssl_verification():
49-
authenticator = IAMAuthenticator(apikey='my_apikey', disable_ssl_verification=True)
50+
authenticator = IAMAuthenticator(
51+
apikey='my_apikey', disable_ssl_verification=True)
5052
assert authenticator.token_manager.disable_ssl_verification is True
5153

5254
authenticator.set_disable_ssl_verification(False)
@@ -55,7 +57,8 @@ def test_disable_ssl_verification():
5557

5658
def test_invalid_disable_ssl_verification_type():
5759
with pytest.raises(TypeError) as err:
58-
authenticator = IAMAuthenticator(apikey='my_apikey', disable_ssl_verification='True')
60+
authenticator = IAMAuthenticator(
61+
apikey='my_apikey', disable_ssl_verification='True')
5962
assert str(err.value) == 'disable_ssl_verification must be a bool'
6063

6164
authenticator = IAMAuthenticator(apikey='my_apikey')

test/test_no_auth_authenticator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# pylint: disable=missing-docstring
22

3-
from ibm_cloud_sdk_core.authenticators import NoAuthAuthenticator
3+
from ibm_cloud_sdk_core.authenticators import NoAuthAuthenticator, Authenticator
44

55

66
def test_no_auth_authenticator():
77
authenticator = NoAuthAuthenticator()
88
assert authenticator is not None
9-
assert authenticator.authentication_type == 'noAuth'
9+
assert authenticator.authentication_type() == Authenticator.AUTHTYPE_NOAUTH
1010

1111
authenticator.validate()
1212

0 commit comments

Comments
 (0)