moto icon indicating copy to clipboard operation
moto copied to clipboard

cognito-idp admin_get_user Username argument can be sub

Open jordital opened this issue 1 year ago • 1 comments

Running moto==5.0.2

According to admin_get_user boto3 documentation, it is possible to use sub in the request. Documentation reads:

If username isn’t an alias attribute in your user pool, you can also use their sub in this request.

The following code demonstrates admin_create_user fails when sub is used. This code works in AWS

import boto3
from moto import mock_aws


@mock_aws
def test_admin_get_user():
    cognito = boto3.client("cognito-idp")

    pool = cognito.create_user_pool(
        PoolName="test",
    )

    cognito_pool_id = pool["UserPool"]["Id"]

    email = "[email protected]"

    response = cognito.admin_create_user(
        UserPoolId=cognito_pool_id,
        Username=email,
        UserAttributes=[
            {"Name": "email", "Value": email},
        ],
    )

    user_sub = next(
        filter(
            lambda a: a["Name"] == "sub",
            response["User"]["Attributes"],
        )
    )["Value"]

    # this one works
    cognito.admin_get_user(
        UserPoolId=cognito_pool_id,
        Username=email,
    )

    # this one raises botocore.errorfactory.UserNotFoundException
    cognito.admin_get_user(
        UserPoolId=cognito_pool_id,
        Username=user_sub,
    )

jordital avatar Feb 21 '24 01:02 jordital

Hi @jordital - if I run your example (as is - no changes whatsoever) against AWS, the last call fails as well - so Moto behaves exactly the same, as far as I can tell.

The documentation is a bit ambiguous, but I read it as (emphasis mine):

If and only if username isn’t an alias attribute in your user pool, you can also use their sub in this request.

If you create a userpool where the UsernameAttributes does not contain username, AWS and Moto do allow you to use the sub as a username:

def test_admin_get_user__with_sub():
    conn = boto3.client("cognito-idp", "us-west-2")

    username = "[email protected]"
    user_pool_id = conn.create_user_pool(
        PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
    )["UserPool"]["Id"]
    attrs = conn.admin_create_user(
        UserPoolId=user_pool_id,
        Username=username,
    )["User"]["Attributes"]

    # We can use sub here, because we don't have a regular username
    sub = [p["Value"] for p in attrs if p["Name"] == "sub"][0]
    conn.admin_get_user(UserPoolId=user_pool_id, Username=sub)

bblommers avatar Feb 21 '24 20:02 bblommers