Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise exception if partial credentials are found #331

Merged
merged 1 commit into from
Aug 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions botocore/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,16 @@ def load(self):
"""
return True

def _extract_creds_from_mapping(self, mapping, *key_names):
found = []
for key_name in key_names:
try:
found.append(mapping[key_name])
except KeyError:
raise PartialCredentialsError(provider=self.METHOD,
cred_var=key_name)
return found


class InstanceMetadataProvider(CredentialProvider):
METHOD = 'iam-role'
Expand Down Expand Up @@ -302,8 +312,9 @@ def load(self):
"""
if self._mapping['access_key'] in self.environ:
logger.info('Found credentials in environment variables.')
access_key = self.environ[self._mapping['access_key']]
secret_key = self.environ[self._mapping['secret_key']]
access_key, secret_key = self._extract_creds_from_mapping(
self.environ, self._mapping['access_key'],
self._mapping['secret_key'])
token = self._get_session_token()
return Credentials(access_key, secret_key, token,
method=self.METHOD)
Expand Down Expand Up @@ -377,8 +388,8 @@ def load(self):
if self.ACCESS_KEY in config:
logger.info("Found credentials in shared credentials file: %s",
self._creds_filename)
access_key = config[self.ACCESS_KEY]
secret_key = config[self.SECRET_KEY]
access_key, secret_key = self._extract_creds_from_mapping(
config, self.ACCESS_KEY, self.SECRET_KEY)
token = self._get_session_token(config)
return Credentials(access_key, secret_key, token,
method=self.METHOD)
Expand Down Expand Up @@ -429,8 +440,8 @@ def load(self):
if self.ACCESS_KEY in profile_config:
logger.info("Credentials found in config file: %s",
self._config_filename)
access_key = profile_config[self.ACCESS_KEY]
secret_key = profile_config[self.SECRET_KEY]
access_key, secret_key = self._extract_creds_from_mapping(
profile_config, self.ACCESS_KEY, self.SECRET_KEY)
token = self._get_session_token(profile_config)
return Credentials(access_key, secret_key, token,
method=self.METHOD)
Expand Down Expand Up @@ -478,8 +489,8 @@ def load(self):
if self.ACCESS_KEY in credentials:
logger.info("Found credentials in boto config file: %s",
filename)
access_key = credentials[self.ACCESS_KEY]
secret_key = credentials[self.SECRET_KEY]
access_key, secret_key = self._extract_creds_from_mapping(
credentials, self.ACCESS_KEY, self.SECRET_KEY)
return Credentials(access_key, secret_key,
method=self.METHOD)

Expand Down
2 changes: 1 addition & 1 deletion botocore/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class PartialCredentialsError(BotoCoreError):
:ivar cred_var: The missing credential variable name.

"""
fmt = 'Partial credentials found, missing: {cred_var}'
fmt = 'Partial credentials found in {provider}, missing: {cred_var}'


class NoRegionError(BotoCoreError):
Expand Down
49 changes: 49 additions & 0 deletions tests/unit/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ def test_can_override_partial_env_var_mapping(self):
self.assertEqual(creds.secret_key, 'bar')
self.assertEqual(creds.token, 'baz')

def test_partial_creds_is_an_error(self):
# If the user provides an access key, they must also
# provide a secret key. Not doing so will generate an
# error.
environ = {
'AWS_ACCESS_KEY_ID': 'foo',
# Missing the AWS_SECRET_ACCESS_KEY
}
provider = credentials.EnvProvider(environ)
with self.assertRaises(botocore.exceptions.PartialCredentialsError):
creds = provider.load()


class TestSharedCredentialsProvider(BaseEnvVar):
def setUp(self):
Expand All @@ -209,6 +221,19 @@ def test_credential_file_exists_default_profile(self):
self.assertIsNone(creds.token)
self.assertEqual(creds.method, 'shared-credentials-file')

def test_partial_creds_raise_error(self):
self.ini_parser.return_value = {
'default': {
'aws_access_key_id': 'foo',
# Missing 'aws_secret_access_key'.
}
}
provider = credentials.SharedCredentialProvider(
creds_filename='~/.aws/creds', profile_name='default',
ini_parser=self.ini_parser)
with self.assertRaises(botocore.exceptions.PartialCredentialsError):
provider.load()

def test_credentials_file_exists_with_session_token(self):
self.ini_parser.return_value = {
'default': {
Expand Down Expand Up @@ -310,6 +335,18 @@ def test_config_file_errors_ignored(self):
creds = provider.load()
self.assertIsNone(creds)

def test_partial_creds_is_error(self):
profile_config = {
'aws_access_key_id': 'a',
# Missing aws_secret_access_key
}
parsed = {'profiles': {'default': profile_config}}
parser = mock.Mock()
parser.return_value = parsed
provider = credentials.ConfigProvider('cli.cfg', 'default', parser)
with self.assertRaises(botocore.exceptions.PartialCredentialsError):
provider.load()


class TestBotoProvider(BaseEnvVar):
def setUp(self):
Expand Down Expand Up @@ -368,6 +405,18 @@ def test_no_boto_config_file_exists(self):
creds = provider.load()
self.assertIsNone(creds)

def test_partial_creds_is_error(self):
ini_parser = mock.Mock()
ini_parser.return_value = {
'Credentials': {
'aws_access_key_id': 'a',
# Missing aws_secret_access_key.
}
}
provider = credentials.BotoProvider(environ={},
ini_parser=ini_parser)
with self.assertRaises(botocore.exceptions.PartialCredentialsError):
creds = provider.load()


class TestOriginalEC2Provider(BaseEnvVar):
Expand Down