From c60fb068e1138423690dd9fe500e31761d40efec Mon Sep 17 00:00:00 2001 From: Maksymilian Babarowski Date: Tue, 12 Oct 2021 00:31:40 +0200 Subject: [PATCH] =?UTF-8?q?cognito-idp=20=E2=80=93=20Added=20format=20vali?= =?UTF-8?q?dation=20and=20implemented=20prefix=20operator=20for=20Filter?= =?UTF-8?q?=20param=20of=20list=5Fusers=20(#4388)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- moto/cognitoidp/responses.py | 14 ++++++-- tests/test_cognitoidp/test_cognitoidp.py | 41 ++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/moto/cognitoidp/responses.py b/moto/cognitoidp/responses.py index 4f5ba9846..3ad1a35b8 100644 --- a/moto/cognitoidp/responses.py +++ b/moto/cognitoidp/responses.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import json import os +import re from moto.core.responses import BaseResponse from .models import cognitoidp_backends, find_region_by_value, UserStatus @@ -332,18 +333,25 @@ class CognitoIdpResponse(BaseResponse): "status": lambda u: "Enabled" if u.enabled else "Disabled", "username": lambda u: u.username, } - name, value = filt.replace('"', "").replace(" ", "").split("=") + comparisons = {"=": lambda x, y: x == y, "^=": lambda x, y: x.startswith(y)} + + match = re.match(r"([\w:]+)\s*(=|\^=)\s*\"(.*)\"", filt) + if match: + name, op, value = match.groups() + else: + raise InvalidParameterException("Error while parsing filter") + compare = comparisons[op] users = [ user for user in users if [ attr for attr in user.attributes - if attr["Name"] == name and attr["Value"] == value + if attr["Name"] == name and compare(attr["Value"], value) ] or ( name in inherent_attributes - and inherent_attributes[name](user) == value + and compare(inherent_attributes[name](user), value) ) ] response = {"Users": [user.to_json(extended=True) for user in users]} diff --git a/tests/test_cognitoidp/test_cognitoidp.py b/tests/test_cognitoidp/test_cognitoidp.py index 18c9ac2d4..a419f0a86 100644 --- a/tests/test_cognitoidp/test_cognitoidp.py +++ b/tests/test_cognitoidp/test_cognitoidp.py @@ -1209,18 +1209,55 @@ def test_list_users(): UserAttributes=[{"Name": "phone_number", "Value": "+33666666666"}], ) result = conn.list_users( - UserPoolId=user_pool_id, Filter='phone_number="+33666666666' + UserPoolId=user_pool_id, Filter='phone_number="+33666666666"' ) result["Users"].should.have.length_of(1) result["Users"][0]["Username"].should.equal(username_bis) # checking Filter with space result = conn.list_users( - UserPoolId=user_pool_id, Filter='phone_number = "+33666666666' + UserPoolId=user_pool_id, Filter='phone_number = "+33666666666"' ) result["Users"].should.have.length_of(1) result["Users"][0]["Username"].should.equal(username_bis) + user0_username = "user0@example.com" + conn.admin_create_user( + UserPoolId=user_pool_id, + Username=user0_username, + UserAttributes=[{"Name": "phone_number", "Value": "+48555555555"}], + ) + + # checking Filter with prefix operator + result = conn.list_users(UserPoolId=user_pool_id, Filter='phone_number ^= "+48"') + result["Users"].should.have.length_of(1) + result["Users"][0]["Username"].should.equal(user0_username) + + # empty value Filter should also be supported + result = conn.list_users(UserPoolId=user_pool_id, Filter='family_name=""') + result["Users"].should.have.length_of(0) + + +@mock_cognitoidp +def test_list_users_incorrect_filter(): + conn = boto3.client("cognito-idp", "us-west-2") + + user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"] + + with pytest.raises(conn.exceptions.InvalidParameterException) as exc: + conn.list_users(UserPoolId=user_pool_id, Filter="username = foo") + _assert_filter_parsing_error(exc) + + with pytest.raises(conn.exceptions.InvalidParameterException) as exc: + conn.list_users(UserPoolId=user_pool_id, Filter="username=") + _assert_filter_parsing_error(exc) + + +def _assert_filter_parsing_error(exc): + err = exc.value.response["Error"] + assert err["Code"].should.equal("InvalidParameterException") + assert err["Message"].should.equal("Error while parsing filter") + @mock_cognitoidp def test_list_users_inherent_attributes():