Skip to content

Commit c50d2bb

Browse files
committed
feat(config): get_authenticator_from_environment for loading from env
1 parent 52d6108 commit c50d2bb

File tree

6 files changed

+198
-186
lines changed

6 files changed

+198
-186
lines changed

ibm_cloud_sdk_core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
from .jwt_token_manager import JWTTokenManager
2020
from .cp4d_token_manager import CP4DTokenManager
2121
from .api_exception import ApiException
22-
from .utils import datetime_to_string, string_to_datetime
22+
from .utils import datetime_to_string, string_to_datetime, get_authenticator_from_environment

ibm_cloud_sdk_core/base_service.py

Lines changed: 10 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import requests
2323
from requests.structures import CaseInsensitiveDict
2424
from .version import __version__
25-
from .utils import has_bad_first_or_last_char, remove_null_values, cleanup_values
25+
from .utils import has_bad_first_or_last_char, remove_null_values, cleanup_values, read_from_external_sources
2626
from .detailed_response import DetailedResponse
2727
from .api_exception import ApiException
2828
from .authenticators import Authenticator, BasicAuthenticator, BearerTokenAuthenticator, CloudPakForDataAuthenticator, IamAuthenticator, NoauthAuthenticator
@@ -34,25 +34,19 @@
3434

3535

3636
class BaseService(object):
37-
DEFAULT_CREDENTIALS_FILE_NAME = 'ibm-credentials.env'
37+
3838
SDK_NAME = 'ibm-python-sdk-core'
3939

4040
def __init__(self,
41-
vcap_services_name,
4241
url,
4342
authenticator=None,
4443
disable_ssl_verification=False,
4544
display_name=None):
4645
"""
47-
It loads credentials with the following preference:
48-
1) Credentials explicitly set in the authenticator
49-
2) Credentials loaded from credentials file if present
50-
3) Credentials loaded from VCAP_SERVICES environment variable
51-
52-
:attr str vcap_services_name: The vcap service name
5346
:attr str url: The url for service api calls
47+
:attr Athenticator authenticator: The authenticator for authentication
5448
:attr bool disable_ssl_verification: enables/ disabled ssl verification
55-
:attr str display_name the name used for mapping services in credential file
49+
:attr str display_name the name used for mapping services in environment file
5650
"""
5751
self.url = url
5852
self.http_config = {}
@@ -63,114 +57,19 @@ def __init__(self,
6357

6458
self._set_user_agent_header(self._build_user_agent())
6559

66-
# 1. Credentials are passed in constructor
6760
if self.authenticator:
6861
if not isinstance(self.authenticator, Authenticator):
6962
raise ValueError(
7063
'authenticator should be of type Authenticator')
7164

72-
# 2. Credentials from credential file
73-
if display_name and not self.authenticator:
65+
if display_name:
7466
service_name = display_name.replace(' ', '_').lower()
75-
self._load_from_credential_file(service_name)
76-
77-
# 3. Credentials from VCAP
78-
if not self.authenticator:
79-
vcap_service_credentials = self._load_from_vcap_services(
80-
vcap_services_name)
81-
if vcap_service_credentials is not None and isinstance(
82-
vcap_service_credentials, dict):
83-
if vcap_service_credentials.get('username') and vcap_service_credentials.get('password'): # cf
84-
vcap_service_credentials['auth_type'] = 'basic'
85-
elif vcap_service_credentials.get('apikey'): # rc
86-
vcap_service_credentials['auth_type'] = 'iam'
87-
self._set_authenticator_properties(vcap_service_credentials)
88-
self._set_service_properties(vcap_service_credentials)
89-
90-
if not self.authenticator:
91-
self.authenticator = NoauthAuthenticator()
92-
93-
def _load_from_credential_file(self, service_name, separator='='):
94-
"""
95-
Initiates the credentials based on the credential file
67+
config = read_from_external_sources(service_name)
68+
if config.get('url'):
69+
self.url = config.get('url')
70+
if config.get('disable_ssl'):
71+
self.disable_ssl_verification = config.get('disable_ssl')
9672

97-
:param str service_name: The service name
98-
:param str separator: the separator for key value pair
99-
"""
100-
# File path specified by an env variable
101-
credential_file_path = os.getenv('IBM_CREDENTIALS_FILE')
102-
103-
# Home directory
104-
if credential_file_path is None:
105-
file_path = join(
106-
expanduser('~'), self.DEFAULT_CREDENTIALS_FILE_NAME)
107-
if isfile(file_path):
108-
credential_file_path = file_path
109-
110-
# Top-level of the project directory
111-
if credential_file_path is None:
112-
file_path = join(
113-
dirname(dirname(abspath(__file__))),
114-
self.DEFAULT_CREDENTIALS_FILE_NAME)
115-
if isfile(file_path):
116-
credential_file_path = file_path
117-
118-
properties = {}
119-
if credential_file_path is not None:
120-
with open(credential_file_path, 'r') as fp:
121-
for line in fp:
122-
key_val = line.strip().split(separator)
123-
if len(key_val) == 2:
124-
key = key_val[0].lower()
125-
value = key_val[1]
126-
if service_name in key:
127-
index = key.find('_')
128-
if index != -1:
129-
properties[key[index + 1:]] = value
130-
131-
if properties:
132-
self._set_authenticator_properties(properties)
133-
self._set_service_properties(properties)
134-
135-
def _set_authenticator_properties(self, properties):
136-
auth_type = properties.get('auth_type')
137-
if auth_type == 'basic':
138-
self.authenticator = BasicAuthenticator(
139-
username=properties.get('username'),
140-
password=properties.get('password'))
141-
elif auth_type == 'bearerToken':
142-
self.authenticator = BearerTokenAuthenticator(
143-
bearer_token=properties.get('bearer_token'))
144-
elif auth_type == 'cp4d':
145-
self.authenticator = CloudPakForDataAuthenticator(
146-
username=properties.get('username'),
147-
password=properties.get('password'),
148-
url=properties.get('auth_url'),
149-
disable_ssl_verification=properties.get('auth_disable_ssl'))
150-
elif auth_type == 'iam':
151-
self.authenticator = IamAuthenticator(
152-
apikey=properties.get('apikey'),
153-
url=properties.get('auth_url'),
154-
client_id=properties.get('client_id'),
155-
client_secret=properties.get('client_secret'),
156-
disable_ssl_verification=properties.get('auth_disable_ssl'))
157-
elif auth_type == 'noauth':
158-
self.authenticator = NoauthAuthenticator()
159-
160-
def _set_service_properties(self, properties):
161-
if 'url' in properties:
162-
self.url = properties.get('url')
163-
if 'disable_ssl' in properties:
164-
self.disable_ssl_verification = properties.get('disable_ssl')
165-
166-
def _load_from_vcap_services(self, service_name):
167-
vcap_services = os.getenv('VCAP_SERVICES')
168-
if vcap_services is not None:
169-
services = json_import.loads(vcap_services)
170-
if service_name in services:
171-
return services[service_name][0]['credentials']
172-
else:
173-
return None
17473

17574
def _get_system_info(self):
17675
return '{0} {1} {2}'.format(
@@ -237,7 +136,6 @@ def send(self, request, **kwargs):
237136
kwargs['verify'] = False
238137

239138
response = requests.request(**request, cookies=self.jar, **kwargs)
240-
print(response.headers)
241139

242140
if 200 <= response.status_code <= 299:
243141
if response.status_code == 204 or request['method'] == 'HEAD':

ibm_cloud_sdk_core/utils.py

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
# limitations under the License.
1616

1717
import dateutil.parser as date_parser
18+
from os.path import dirname, isfile, join, expanduser, abspath, basename
19+
from os import getenv
20+
import json as json_import
1821

1922
def has_bad_first_or_last_char(str):
2023
return str is not None and (str.startswith('{') or str.startswith('"') or str.endswith('}') or str.endswith('"'))
@@ -39,7 +42,7 @@ def datetime_to_string(datetime):
3942
"""
4043
Serializes a datetime to a string.
4144
:param datetime: datetime value
42-
:return: string. containing iso8601 format date string
45+
:return: string containing iso8601 format date string
4346
"""
4447
return datetime.isoformat().replace('+00:00', 'Z')
4548

@@ -50,3 +53,109 @@ def string_to_datetime(string):
5053
:return: datetime.
5154
"""
5255
return date_parser.parse(string)
56+
57+
def get_authenticator_from_environment(service_name):
58+
"""
59+
Checks the credentials file and VCAP_SERVICES environment variable
60+
:param service_name: The service name
61+
:return: the authenticator
62+
"""
63+
authenticator = None
64+
# 1. Credentials from credential file
65+
config = read_from_external_sources(service_name)
66+
if config:
67+
authenticator = contruct_authenticator(config)
68+
69+
# 2. Credentials from VCAP
70+
if not authenticator:
71+
config = read_from_vcap_services(service_name)
72+
if config:
73+
authenticator = contruct_authenticator(config)
74+
75+
return authenticator
76+
77+
def read_from_external_sources(service_name, separator='='):
78+
"""
79+
:param str service_name: The service name
80+
:return dict config: parsed key values pairs
81+
"""
82+
service_name = service_name.lower()
83+
DEFAULT_CREDENTIALS_FILE_NAME = 'ibm-credentials.env'
84+
85+
# File path specified by an env variable
86+
credential_file_path = getenv('IBM_CREDENTIALS_FILE')
87+
88+
# Home directory
89+
if credential_file_path is None:
90+
file_path = join(expanduser('~'), DEFAULT_CREDENTIALS_FILE_NAME)
91+
if isfile(file_path):
92+
credential_file_path = file_path
93+
94+
# Top-level of the project directory
95+
if credential_file_path is None:
96+
file_path = join(
97+
dirname(dirname(abspath(__file__))), DEFAULT_CREDENTIALS_FILE_NAME)
98+
if isfile(file_path):
99+
credential_file_path = file_path
100+
101+
config = {}
102+
if credential_file_path is not None:
103+
with open(credential_file_path, 'r') as fp:
104+
for line in fp:
105+
key_val = line.strip().split(separator)
106+
if len(key_val) == 2:
107+
key = key_val[0].lower()
108+
value = key_val[1]
109+
if service_name in key:
110+
index = key.find('_')
111+
if index != -1:
112+
config[key[index + 1:]] = value
113+
114+
return config
115+
116+
def read_from_vcap_services(service_name):
117+
vcap_services = getenv('VCAP_SERVICES')
118+
vcap_service_credentials = None
119+
if vcap_services:
120+
services = json_import.loads(vcap_services)
121+
122+
if service_name in services:
123+
vcap_service_credentials = services[service_name][0]['credentials']
124+
if vcap_service_credentials is not None and isinstance(vcap_service_credentials, dict):
125+
if vcap_service_credentials.get('username') and vcap_service_credentials.get('password'): # cf
126+
vcap_service_credentials['auth_type'] = 'basic'
127+
elif vcap_service_credentials.get('apikey'): # rc
128+
vcap_service_credentials['auth_type'] = 'iam'
129+
else: # no other auth mechanism is supported
130+
vcap_service_credentials = None
131+
return vcap_service_credentials
132+
133+
def contruct_authenticator(config):
134+
auth_type = config.get('auth_type')
135+
authenticator = None
136+
from .authenticators import BasicAuthenticator, BearerTokenAuthenticator, CloudPakForDataAuthenticator, IamAuthenticator, NoauthAuthenticator
137+
138+
if auth_type == 'basic':
139+
authenticator = BasicAuthenticator(
140+
username=config.get('username'),
141+
password=config.get('password'))
142+
elif auth_type == 'bearerToken':
143+
authenticator = BearerTokenAuthenticator(
144+
bearer_token=config.get('bearer_token'))
145+
elif auth_type == 'cp4d':
146+
authenticator = CloudPakForDataAuthenticator(
147+
username=config.get('username'),
148+
password=config.get('password'),
149+
url=config.get('auth_url'),
150+
disable_ssl_verification=config.get('auth_disable_ssl'))
151+
elif auth_type == 'iam':
152+
authenticator = IamAuthenticator(
153+
apikey=config.get('apikey'),
154+
url=config.get('auth_url'),
155+
client_id=config.get('client_id'),
156+
client_secret=config.get('client_secret'),
157+
disable_ssl_verification=config.get('auth_disable_ssl'))
158+
elif auth_type == 'noauth':
159+
authenticator = NoauthAuthenticator()
160+
161+
return authenticator

resources/ibm-credentials-iam.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
WATSON_APIKEY=5678efgh
22
WATSON_URL=https://gateway-s.watsonplatform.net/watson/api
3-
WATSON_AUTH_TYPE=iam
3+
WATSON_AUTH_TYPE=iam
4+
WATSON_DISABLE_SSL=False

0 commit comments

Comments
 (0)