From 588b50f5c1a3600d0ce59e4df6fccf843770a2d9 Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Sat, 10 Feb 2024 10:53:45 +0000 Subject: [PATCH] CognitoIDP: Allow public actions even if IAM auth is enabled (#7331) --- moto/core/responses.py | 13 ++++++++++ tests/test_cognitoidp/test_cognitoidp.py | 31 +++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/moto/core/responses.py b/moto/core/responses.py index 6b6306d2b..fb88e837b 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -143,6 +143,14 @@ class _TemplateEnvironmentMixin(object): class ActionAuthenticatorMixin(object): request_count: ClassVar[int] = 0 + PUBLIC_OPERATIONS = [ + "AWSCognitoIdentityProviderService.ConfirmSignUp", + "AWSCognitoIdentityProviderService.GetUser", + "AWSCognitoIdentityProviderService.ForgotPassword", + "AWSCognitoIdentityProviderService.InitiateAuth", + "AWSCognitoIdentityProviderService.SignUp", + ] + def _authenticate_and_authorize_action( self, iam_request_cls: type, resource: str = "*" ) -> None: @@ -150,6 +158,11 @@ class ActionAuthenticatorMixin(object): ActionAuthenticatorMixin.request_count >= settings.INITIAL_NO_AUTH_ACTION_COUNT ): + if ( + self.headers.get("X-Amz-Target") # type: ignore[attr-defined] + in ActionAuthenticatorMixin.PUBLIC_OPERATIONS + ): + return parsed_url = urlparse(self.uri) # type: ignore[attr-defined] path = parsed_url.path if parsed_url.query: diff --git a/tests/test_cognitoidp/test_cognitoidp.py b/tests/test_cognitoidp/test_cognitoidp.py index 45456b770..a9d42680f 100644 --- a/tests/test_cognitoidp/test_cognitoidp.py +++ b/tests/test_cognitoidp/test_cognitoidp.py @@ -19,6 +19,7 @@ import moto.cognitoidp.models from moto import mock_aws, settings from moto.cognitoidp.utils import create_id from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID +from moto.core import set_initial_no_auth_action_count @mock_aws @@ -2357,6 +2358,7 @@ def test_get_user(): @mock_aws +@set_initial_no_auth_action_count(0) def test_get_user_unknown_accesstoken(): conn = boto3.client("cognito-idp", "us-west-2") with pytest.raises(ClientError) as ex: @@ -3047,6 +3049,7 @@ def test_change_password__using_custom_user_agent_header(): @mock_aws +@set_initial_no_auth_action_count(2) def test_forgot_password(): conn = boto3.client("cognito-idp", "us-west-2") user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"] @@ -3913,15 +3916,22 @@ def test_confirm_sign_up(): client_id = conn.create_user_pool_client( UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True )["UserPoolClient"]["ClientId"] + _signup_and_confirm(client_id, conn, password, username) + + result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username) + assert result["UserStatus"] == "CONFIRMED" + + +@set_initial_no_auth_action_count(0) +def _signup_and_confirm(client_id, conn, password, username): + # Also verify Authentication works for these actions + # There are no IAM policies, but they should be public - accessible by anyone conn.sign_up(ClientId=client_id, Username=username, Password=password) conn.confirm_sign_up( ClientId=client_id, Username=username, ConfirmationCode="123456" ) - result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username) - assert result["UserStatus"] == "CONFIRMED" - @mock_aws def test_confirm_sign_up_with_username_attributes(): @@ -4857,6 +4867,21 @@ def test_login_denied_if_account_disabled(): assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 +@mock_aws +# Also validate that we don't need IAM policies, as this operation should be publicly accessible +@set_initial_no_auth_action_count(0) +def test_initiate_auth_with_invalid_user_pool(): + conn = boto3.client("cognito-idp", "us-west-2") + with pytest.raises(ClientError) as exc: + conn.initiate_auth( + ClientId="unknown", + AuthFlow="USER_PASSWORD_AUTH", + AuthParameters={"USERNAME": "user", "PASSWORD": "pass"}, + ) + err = exc.value.response["Error"] + assert err["Code"] == "ResourceNotFoundException" + + # Test will retrieve public key from cognito.amazonaws.com/.well-known/jwks.json, # which isnt mocked in ServerMode if not settings.TEST_SERVER_MODE: