mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Allow aws credential skip validation (#22991)
* Allow aws credential skip validation * Don't validate the auto-created default profile
This commit is contained in:
parent
3f69d0283d
commit
73a473ac29
@ -20,6 +20,7 @@ from .const import (
|
|||||||
CONF_REGION,
|
CONF_REGION,
|
||||||
CONF_SECRET_ACCESS_KEY,
|
CONF_SECRET_ACCESS_KEY,
|
||||||
CONF_SERVICE,
|
CONF_SERVICE,
|
||||||
|
CONF_VALIDATE,
|
||||||
DATA_CONFIG,
|
DATA_CONFIG,
|
||||||
DATA_HASS_CONFIG,
|
DATA_HASS_CONFIG,
|
||||||
DATA_SESSIONS,
|
DATA_SESSIONS,
|
||||||
@ -34,10 +35,15 @@ AWS_CREDENTIAL_SCHEMA = vol.Schema(
|
|||||||
vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
|
vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
|
||||||
vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
|
vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
|
||||||
vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
|
vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
|
||||||
|
vol.Optional(CONF_VALIDATE, default=True): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
DEFAULT_CREDENTIAL = [{CONF_NAME: "default", CONF_PROFILE_NAME: "default"}]
|
DEFAULT_CREDENTIAL = [{
|
||||||
|
CONF_NAME: "default",
|
||||||
|
CONF_PROFILE_NAME: "default",
|
||||||
|
CONF_VALIDATE: False,
|
||||||
|
}]
|
||||||
|
|
||||||
SUPPORTED_SERVICES = ["lambda", "sns", "sqs"]
|
SUPPORTED_SERVICES = ["lambda", "sns", "sqs"]
|
||||||
|
|
||||||
@ -168,6 +174,7 @@ async def _validate_aws_credentials(hass, credential):
|
|||||||
else:
|
else:
|
||||||
session = aiobotocore.AioSession(loop=hass.loop)
|
session = aiobotocore.AioSession(loop=hass.loop)
|
||||||
|
|
||||||
|
if credential[CONF_VALIDATE]:
|
||||||
async with session.create_client("iam", **aws_config) as client:
|
async with session.create_client("iam", **aws_config) as client:
|
||||||
await client.get_user()
|
await client.get_user()
|
||||||
|
|
||||||
|
@ -14,3 +14,4 @@ CONF_PROFILE_NAME = "profile_name"
|
|||||||
CONF_REGION = "region_name"
|
CONF_REGION = "region_name"
|
||||||
CONF_SECRET_ACCESS_KEY = "aws_secret_access_key"
|
CONF_SECRET_ACCESS_KEY = "aws_secret_access_key"
|
||||||
CONF_SERVICE = "service"
|
CONF_SERVICE = "service"
|
||||||
|
CONF_VALIDATE = "validate"
|
||||||
|
@ -10,15 +10,19 @@ class MockAioSession:
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Init a mock session."""
|
"""Init a mock session."""
|
||||||
|
self.get_user = CoroutineMock()
|
||||||
|
self.invoke = CoroutineMock()
|
||||||
|
self.publish = CoroutineMock()
|
||||||
|
self.send_message = CoroutineMock()
|
||||||
|
|
||||||
def create_client(self, *args, **kwargs): # pylint: disable=no-self-use
|
def create_client(self, *args, **kwargs): # pylint: disable=no-self-use
|
||||||
"""Create a mocked client."""
|
"""Create a mocked client."""
|
||||||
return MagicMock(
|
return MagicMock(
|
||||||
__aenter__=CoroutineMock(return_value=CoroutineMock(
|
__aenter__=CoroutineMock(return_value=CoroutineMock(
|
||||||
get_user=CoroutineMock(), # iam
|
get_user=self.get_user, # iam
|
||||||
invoke=CoroutineMock(), # lambda
|
invoke=self.invoke, # lambda
|
||||||
publish=CoroutineMock(), # sns
|
publish=self.publish, # sns
|
||||||
send_message=CoroutineMock(), # sqs
|
send_message=self.send_message, # sqs
|
||||||
)),
|
)),
|
||||||
__aexit__=CoroutineMock()
|
__aexit__=CoroutineMock()
|
||||||
)
|
)
|
||||||
@ -35,7 +39,10 @@ async def test_empty_config(hass):
|
|||||||
sessions = hass.data[aws.DATA_SESSIONS]
|
sessions = hass.data[aws.DATA_SESSIONS]
|
||||||
assert sessions is not None
|
assert sessions is not None
|
||||||
assert len(sessions) == 1
|
assert len(sessions) == 1
|
||||||
assert isinstance(sessions.get('default'), MockAioSession)
|
session = sessions.get('default')
|
||||||
|
assert isinstance(session, MockAioSession)
|
||||||
|
# we don't validate auto-created default profile
|
||||||
|
session.get_user.assert_not_awaited()
|
||||||
|
|
||||||
|
|
||||||
async def test_empty_credential(hass):
|
async def test_empty_credential(hass):
|
||||||
@ -55,7 +62,8 @@ async def test_empty_credential(hass):
|
|||||||
sessions = hass.data[aws.DATA_SESSIONS]
|
sessions = hass.data[aws.DATA_SESSIONS]
|
||||||
assert sessions is not None
|
assert sessions is not None
|
||||||
assert len(sessions) == 1
|
assert len(sessions) == 1
|
||||||
assert isinstance(sessions.get('default'), MockAioSession)
|
session = sessions.get('default')
|
||||||
|
assert isinstance(session, MockAioSession)
|
||||||
|
|
||||||
assert hass.services.has_service('notify', 'new_lambda_test') is True
|
assert hass.services.has_service('notify', 'new_lambda_test') is True
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -64,6 +72,7 @@ async def test_empty_credential(hass):
|
|||||||
{'message': 'test', 'target': 'ARN'},
|
{'message': 'test', 'target': 'ARN'},
|
||||||
blocking=True
|
blocking=True
|
||||||
)
|
)
|
||||||
|
session.invoke.assert_awaited_once()
|
||||||
|
|
||||||
|
|
||||||
async def test_profile_credential(hass):
|
async def test_profile_credential(hass):
|
||||||
@ -88,7 +97,8 @@ async def test_profile_credential(hass):
|
|||||||
sessions = hass.data[aws.DATA_SESSIONS]
|
sessions = hass.data[aws.DATA_SESSIONS]
|
||||||
assert sessions is not None
|
assert sessions is not None
|
||||||
assert len(sessions) == 1
|
assert len(sessions) == 1
|
||||||
assert isinstance(sessions.get('test'), MockAioSession)
|
session = sessions.get('test')
|
||||||
|
assert isinstance(session, MockAioSession)
|
||||||
|
|
||||||
assert hass.services.has_service('notify', 'sns_test') is True
|
assert hass.services.has_service('notify', 'sns_test') is True
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -97,6 +107,7 @@ async def test_profile_credential(hass):
|
|||||||
{'title': 'test', 'message': 'test', 'target': 'ARN'},
|
{'title': 'test', 'message': 'test', 'target': 'ARN'},
|
||||||
blocking=True
|
blocking=True
|
||||||
)
|
)
|
||||||
|
session.publish.assert_awaited_once()
|
||||||
|
|
||||||
|
|
||||||
async def test_access_key_credential(hass):
|
async def test_access_key_credential(hass):
|
||||||
@ -128,7 +139,8 @@ async def test_access_key_credential(hass):
|
|||||||
sessions = hass.data[aws.DATA_SESSIONS]
|
sessions = hass.data[aws.DATA_SESSIONS]
|
||||||
assert sessions is not None
|
assert sessions is not None
|
||||||
assert len(sessions) == 2
|
assert len(sessions) == 2
|
||||||
assert isinstance(sessions.get('key'), MockAioSession)
|
session = sessions.get('key')
|
||||||
|
assert isinstance(session, MockAioSession)
|
||||||
|
|
||||||
assert hass.services.has_service('notify', 'sns_test') is True
|
assert hass.services.has_service('notify', 'sns_test') is True
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -137,6 +149,7 @@ async def test_access_key_credential(hass):
|
|||||||
{'title': 'test', 'message': 'test', 'target': 'ARN'},
|
{'title': 'test', 'message': 'test', 'target': 'ARN'},
|
||||||
blocking=True
|
blocking=True
|
||||||
)
|
)
|
||||||
|
session.publish.assert_awaited_once()
|
||||||
|
|
||||||
|
|
||||||
async def test_notify_credential(hass):
|
async def test_notify_credential(hass):
|
||||||
@ -197,3 +210,28 @@ async def test_notify_credential_profile(hass):
|
|||||||
{'message': 'test', 'target': 'ARN'},
|
{'message': 'test', 'target': 'ARN'},
|
||||||
blocking=True
|
blocking=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_credential_skip_validate(hass):
|
||||||
|
"""Test credential can skip validate."""
|
||||||
|
with async_patch('aiobotocore.AioSession', new=MockAioSession):
|
||||||
|
await async_setup_component(hass, 'aws', {
|
||||||
|
'aws': {
|
||||||
|
'credentials': [
|
||||||
|
{
|
||||||
|
'name': 'key',
|
||||||
|
'aws_access_key_id': 'not-valid',
|
||||||
|
'aws_secret_access_key': 'dont-care',
|
||||||
|
'validate': False
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
sessions = hass.data[aws.DATA_SESSIONS]
|
||||||
|
assert sessions is not None
|
||||||
|
assert len(sessions) == 1
|
||||||
|
session = sessions.get('key')
|
||||||
|
assert isinstance(session, MockAioSession)
|
||||||
|
session.get_user.assert_not_awaited()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user