from enum import Enum
import getpass
import os
from . import util
[docs]class CredentialType(Enum):
"""list of credentials types supported"""
UserPassword = 'user_password'
ApiKeyAndId = 'api_key_and_api_id'
[docs]def get_credentials(name, global_config, credentials, extra_parameters=None):
"""Get structured form of specified credential based on its type and ready to be passed to any api
:param name: name of the credential
:type name: str
:param global_config: credential global configuration
:type global_config: dict
:param credentials: structured credentials dict
:type credentials: dict
:param extra_parameters: extra parameters to add to current credential
:type extra_parameters: dict
:return: structured credentials
:rtype: dict
"""
result = credentials.get(name, {})
if result.get('type') is None:
# retrieve credentials global configuration
credentials_config = global_config[name]
# retrieve credentials based on credentials type
# credential type should be valid as already verified as part of ssl blueprint validation
credential_type = CredentialType[credentials_config['type']]
# ability to customize fields separator in command line from global credential section, default to ':'
separator = credentials_config.get('separator')
# no need for an 'else' as every credential type part of the enum is expected to be implemented here
if credential_type == CredentialType.UserPassword:
result = get_user_password(name=name, credentials=credentials, separator=separator)
elif credential_type == CredentialType.ApiKeyAndId:
result = get_api_key_and_id(name=name, credentials=credentials, separator=separator)
# update custom parameters
if extra_parameters:
result.update(extra_parameters)
return result
def _get_credential(name, credentials, credential_type, separator, parameters, sensitive_params=None):
# initialize result with correct structure this credential type
result = {
'type': credential_type,
}
for parameter in parameters:
result[parameter] = None
# check first if this credential is already in input credentials dict,
# this can happen in 2 cases:
# 1. if provided in command line input
# 2. if it has been already used once
if credentials and name in credentials:
result.update(credentials[name])
# credential is not complete, let try different ways to get missing information
missing_parameters = [param_name for param_name in result if result[param_name] is None]
if any(missing_parameters):
# first, if we have a raw content to parse
raw_content = result.get('raw_content')
if raw_content is not None:
# try to split as much as we expect parameters, using specified separator or ':' by default
credentials_input = raw_content.split(separator or ':', len(parameters) - 1)
for index, parameter in enumerate(parameters):
if len(credentials_input) >= index + 1:
result[parameter] = credentials_input[index]
# only keep formatted data
del result['raw_content']
# finally if we still miss some data
for parameter in parameters:
if result[parameter] is None:
# check environment variables first
# format for env variable name is "CREDENTIAL_NAME + _ + PARAMETER_NAME"
result[parameter] = os.getenv('{}_{}'.format(name, parameter).upper())
# and finally, if still missing, ask interactively to the user
if result[parameter] is None:
prompt_str = '{} {}:'.format(name.title(), parameter)
if parameter in sensitive_params or []:
result[parameter] = getpass.getpass(prompt_str)
else:
result[parameter] = raw_input(prompt_str) if util.PY2 else input(prompt_str) # noqa
return result
[docs]def get_user_password(name, credentials=None, separator=None):
return _get_credential(
name=name,
credentials=credentials,
credential_type=CredentialType.UserPassword,
separator=separator,
parameters=['username', 'password'],
sensitive_params=['password']
)
[docs]def get_api_key_and_id(name, credentials=None, separator=None):
return _get_credential(
name=name,
credentials=credentials,
separator=separator,
credential_type=CredentialType.ApiKeyAndId,
parameters=['api_key', 'api_id'],
sensitive_params=['api_key', 'api_id']
)