moto/tests/test_cognitoidp/test_cognitoidp.py

4931 lines
172 KiB
Python

import base64
import datetime
import hashlib
import hmac
import json
import os
import random
import re
import uuid
from unittest import SkipTest, mock
import boto3
import pytest
import requests
from botocore.exceptions import ClientError, ParamValidationError
from jose import jws, jwt
import moto.cognitoidp.models
from moto import mock_cognitoidp, settings
from moto.cognitoidp.utils import create_id
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
@mock_cognitoidp
def test_create_user_pool():
conn = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
value = str(uuid.uuid4())
result = conn.create_user_pool(PoolName=name, LambdaConfig={"PreSignUp": value})
assert (
result["UserPool"]["Arn"]
== f"arn:aws:cognito-idp:us-west-2:{ACCOUNT_ID}:userpool/{result['UserPool']['Id']}"
)
assert result["UserPool"]["Name"] == name
assert result["UserPool"]["LambdaConfig"]["PreSignUp"] == value
@mock_cognitoidp
def test_create_user_pool__overwrite_template_messages():
client = boto3.client("cognito-idp", "us-east-2")
resp = client.create_user_pool(
PoolName="test",
VerificationMessageTemplate={
"DefaultEmailOption": "CONFIRM_WITH_LINK",
"EmailMessage": "foo {####} bar",
"EmailMessageByLink": "{##foobar##}",
"EmailSubject": "foobar {####}",
"EmailSubjectByLink": "foobar",
"SmsMessage": "{####} baz",
},
)
pool = resp["UserPool"]
assert pool["SmsVerificationMessage"] == "{####} baz"
assert pool["EmailVerificationSubject"] == "foobar {####}"
assert pool["EmailVerificationMessage"] == "foo {####} bar"
@mock_cognitoidp
def test_create_user_pool_should_have_all_default_attributes_in_schema():
conn = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
result = conn.create_user_pool(PoolName=name)
result_schema = result["UserPool"]["SchemaAttributes"]
result_schema = {s["Name"]: s for s in result_schema}
described_schema = conn.describe_user_pool(UserPoolId=result["UserPool"]["Id"])[
"UserPool"
]["SchemaAttributes"]
described_schema = {s["Name"]: s for s in described_schema}
for schema in result_schema, described_schema:
for (
default_attr_name,
default_attr,
) in moto.cognitoidp.models.CognitoIdpUserPoolAttribute.STANDARD_SCHEMA.items():
attribute = schema[default_attr_name]
assert attribute["Required"] == default_attr["Required"]
assert attribute["AttributeDataType"] == default_attr["AttributeDataType"]
assert attribute["Mutable"] == default_attr["Mutable"]
assert attribute.get("StringAttributeConstraints") == default_attr.get(
"StringAttributeConstraints"
)
assert attribute.get("NumberAttributeConstraints") == default_attr.get(
"NumberAttributeConstraints"
)
assert attribute["DeveloperOnlyAttribute"] is False
@mock_cognitoidp
def test_create_user_pool_unknown_attribute_data_type():
conn = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
attribute_data_type = "Banana"
with pytest.raises(ClientError) as ex:
conn.create_user_pool(
PoolName=name,
Schema=[{"Name": "custom", "AttributeDataType": attribute_data_type}],
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== f"Validation error detected: Value '{attribute_data_type}' failed to satisfy constraint: Member must satisfy enum value set: [Boolean, Number, String, DateTime]"
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_user_pool_custom_attribute_without_data_type():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(PoolName=str(uuid.uuid4()), Schema=[{"Name": "custom"}])
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "Invalid AttributeDataType input, consider using the provided AttributeDataType enum."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_user_pool_custom_attribute_defaults():
conn = boto3.client("cognito-idp", "us-west-2")
res = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{"Name": "string", "AttributeDataType": "String"},
{"Name": "number", "AttributeDataType": "Number"},
],
)
string_attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:string"
)
assert string_attribute["DeveloperOnlyAttribute"] is False
assert string_attribute["Mutable"] is True
number_attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:number"
)
assert number_attribute["DeveloperOnlyAttribute"] is False
assert number_attribute["Mutable"] is True
assert "NumberAttributeConstraints" not in number_attribute
@mock_cognitoidp
def test_create_user_pool_custom_attribute_developer_only():
conn = boto3.client("cognito-idp", "us-west-2")
res = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{
"Name": "banana",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": True,
},
],
)
# Note that this time we are looking for 'dev:xyz' attribute
attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "dev:custom:banana"
)
assert attribute["DeveloperOnlyAttribute"] is True
@mock_cognitoidp
def test_create_user_pool_custom_attribute_required():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{"Name": "banana", "AttributeDataType": "String", "Required": True},
],
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "Required custom attributes are not supported currently."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
@pytest.mark.parametrize(
"attribute",
[
{"Name": "email", "AttributeDataType": "Number"},
{"Name": "email", "DeveloperOnlyAttribute": True},
],
ids=["standard_attribute", "developer_only"],
)
def test_create_user_pool_standard_attribute_with_changed_data_type_or_developer_only(
attribute,
):
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(PoolName=str(uuid.uuid4()), Schema=[attribute])
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== f"You can not change AttributeDataType or set developerOnlyAttribute for standard schema attribute {attribute['Name']}"
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_user_pool_attribute_with_schema():
conn = boto3.client("cognito-idp", "us-west-2")
res = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{
"Name": "string",
"AttributeDataType": "String",
"NumberAttributeConstraints": {"MinValue": "10", "MaxValue": "20"},
"StringAttributeConstraints": {"MinLength": "10", "MaxLength": "20"},
},
{
"Name": "number",
"AttributeDataType": "Number",
"NumberAttributeConstraints": {"MinValue": "10", "MaxValue": "20"},
"StringAttributeConstraints": {"MinLength": "10", "MaxLength": "20"},
},
{
"Name": "boolean",
"AttributeDataType": "Boolean",
"NumberAttributeConstraints": {"MinValue": "10", "MaxValue": "20"},
"StringAttributeConstraints": {"MinLength": "10", "MaxLength": "20"},
},
],
)
string_attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:string"
)
assert string_attribute["StringAttributeConstraints"] == {
"MinLength": "10",
"MaxLength": "20",
}
assert "NumberAttributeConstraints" not in string_attribute
number_attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:number"
)
assert number_attribute["NumberAttributeConstraints"] == {
"MinValue": "10",
"MaxValue": "20",
}
assert "StringAttributeConstraints" not in number_attribute
boolean_attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:boolean"
)
assert "NumberAttributeConstraints" not in boolean_attribute
assert "StringAttributeConstraints" not in boolean_attribute
@mock_cognitoidp
def test_create_user_pool_attribute_partial_schema():
conn = boto3.client("cognito-idp", "us-west-2")
res = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{
"Name": "string_no_min",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MaxLength": "10"},
},
{
"Name": "string_no_max",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MinLength": "10"},
},
{
"Name": "number_no_min",
"AttributeDataType": "Number",
"NumberAttributeConstraints": {"MaxValue": "10"},
},
{
"Name": "number_no_max",
"AttributeDataType": "Number",
"NumberAttributeConstraints": {"MinValue": "10"},
},
],
)
string_no_min = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:string_no_min"
)
string_no_max = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:string_no_max"
)
number_no_min = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:number_no_min"
)
number_no_max = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:number_no_max"
)
assert string_no_min["StringAttributeConstraints"]["MaxLength"] == "10"
assert "MinLength" not in string_no_min["StringAttributeConstraints"]
assert string_no_max["StringAttributeConstraints"]["MinLength"] == "10"
assert "MaxLength" not in string_no_max["StringAttributeConstraints"]
assert number_no_min["NumberAttributeConstraints"]["MaxValue"] == "10"
assert "MinValue" not in number_no_min["NumberAttributeConstraints"]
assert number_no_max["NumberAttributeConstraints"]["MinValue"] == "10"
assert "MaxValue" not in number_no_max["NumberAttributeConstraints"]
@mock_cognitoidp
@pytest.mark.parametrize(
("constraint_type", "attribute"),
[
(
"StringAttributeConstraints",
{
"Name": "email",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MinLength": "invalid_value"},
},
),
(
"StringAttributeConstraints",
{
"Name": "email",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MaxLength": "invalid_value"},
},
),
(
"NumberAttributeConstraints",
{
"Name": "updated_at",
"AttributeDataType": "Number",
"NumberAttributeConstraints": {"MaxValue": "invalid_value"},
},
),
(
"NumberAttributeConstraints",
{
"Name": "updated_at",
"AttributeDataType": "Number",
"NumberAttributeConstraints": {"MinValue": "invalid_value"},
},
),
],
ids=[
"invalid_min_length",
"invalid_max_length",
"invalid_max_value",
"invalid_min_value",
],
)
def test_create_user_pool_invalid_schema_values(constraint_type, attribute):
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(PoolName=str(uuid.uuid4()), Schema=[attribute])
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== f"Invalid {constraint_type} for schema attribute {attribute['Name']}"
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
@pytest.mark.parametrize(
"attribute",
[
{
"Name": "email",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MinLength": "2049"},
},
{
"Name": "email",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MaxLength": "2049"},
},
],
ids=["invalid_min_length", "invalid_max_length"],
)
def test_create_user_pool_string_schema_max_length_over_2048(attribute):
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(PoolName=str(uuid.uuid4()), Schema=[attribute])
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== f"user.{attribute['Name']}: String attributes cannot have a length of more than 2048"
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_user_pool_string_schema_min_bigger_than_max():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{
"Name": "email",
"AttributeDataType": "String",
"StringAttributeConstraints": {"MinLength": "2", "MaxLength": "1"},
}
],
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "user.email: Max length cannot be less than min length."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_user_pool_number_schema_min_bigger_than_max():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{
"Name": "updated_at",
"AttributeDataType": "Number",
"NumberAttributeConstraints": {"MinValue": "2", "MaxValue": "1"},
}
],
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "user.updated_at: Max value cannot be less than min value."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_add_custom_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
custom_attribute = {"Name": "banana", "AttributeDataType": "String"}
res = conn.add_custom_attributes(
UserPoolId=pool_id, CustomAttributes=[custom_attribute]
)
assert res["ResponseMetadata"]["HTTPStatusCode"] == 200
res = conn.describe_user_pool(UserPoolId=pool_id)
described_attribute = next(
attr
for attr in res["UserPool"]["SchemaAttributes"]
if attr["Name"] == "custom:banana"
)
# Skip verification - already covered by create_user_pool with custom attributes
assert described_attribute is not None
@mock_cognitoidp
def test_add_custom_attributes_existing_attribute():
conn = boto3.client("cognito-idp", "us-west-2")
custom_attribute = {
"Name": "banana",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": True,
}
pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), Schema=[custom_attribute]
)["UserPool"]["Id"]
with pytest.raises(ClientError) as ex:
conn.add_custom_attributes(
UserPoolId=pool_id, CustomAttributes=[custom_attribute]
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "custom:banana: Existing attribute already has name dev:custom:banana."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_user_pool_default_id_strategy():
conn = boto3.client("cognito-idp", "us-west-2")
first_pool = conn.create_user_pool(PoolName="default-pool")
second_pool = conn.create_user_pool(PoolName="default-pool")
assert first_pool["UserPool"]["Id"] != second_pool["UserPool"]["Id"]
@mock_cognitoidp
@mock.patch.dict(os.environ, {"MOTO_COGNITO_IDP_USER_POOL_ID_STRATEGY": "HASH"})
def test_create_user_pool_hash_id_strategy_with_equal_pool_name():
if settings.TEST_SERVER_MODE:
raise SkipTest("Cannot set environemnt variables in ServerMode")
conn = boto3.client("cognito-idp", "us-west-2")
first_pool = conn.create_user_pool(PoolName="default-pool")
second_pool = conn.create_user_pool(PoolName="default-pool")
assert first_pool["UserPool"]["Id"] == second_pool["UserPool"]["Id"]
@mock_cognitoidp
@mock.patch.dict(os.environ, {"MOTO_COGNITO_IDP_USER_POOL_ID_STRATEGY": "HASH"})
def test_create_user_pool_hash_id_strategy_with_different_pool_name():
if settings.TEST_SERVER_MODE:
raise SkipTest("Cannot set environemnt variables in ServerMode")
conn = boto3.client("cognito-idp", "us-west-2")
first_pool = conn.create_user_pool(PoolName="first-pool")
second_pool = conn.create_user_pool(PoolName="second-pool")
assert first_pool["UserPool"]["Id"] != second_pool["UserPool"]["Id"]
@mock_cognitoidp
@mock.patch.dict(os.environ, {"MOTO_COGNITO_IDP_USER_POOL_ID_STRATEGY": "HASH"})
def test_create_user_pool_hash_id_strategy_with_different_attributes():
if settings.TEST_SERVER_MODE:
raise SkipTest("Cannot set environemnt variables in ServerMode")
conn = boto3.client("cognito-idp", "us-west-2")
first_pool = conn.create_user_pool(
PoolName="default-pool",
Schema=[
{
"Name": "first",
"AttributeDataType": "String",
}
],
)
second_pool = conn.create_user_pool(
PoolName="default-pool",
Schema=[
{
"Name": "second",
"AttributeDataType": "String",
}
],
)
assert first_pool["UserPool"]["Id"] != second_pool["UserPool"]["Id"]
@mock_cognitoidp
def test_list_user_pools():
conn = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
conn.create_user_pool(PoolName=name)
result = conn.list_user_pools(MaxResults=10)
assert len(result["UserPools"]) == 1
assert result["UserPools"][0]["Name"] == name
@mock_cognitoidp
def test_authorize_user_with_force_password_change_status():
conn = boto3.client("cognito-idp", "us-west-2")
pool_id = conn.create_user_pool(PoolName="TestUserPool")["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=pool_id, ClientName="TestAppClient"
)["UserPoolClient"]["ClientId"]
username = "test@example.com"
temp_password = "Tempor@ryPassword123"
new_password = "NewP@ssword456"
conn.admin_create_user(
UserPoolId=pool_id,
Username=username,
TemporaryPassword=temp_password,
)
# Initiate USER_SRP_AUTH flow
key = bytes(str(temp_password).encode("latin-1"))
msg = bytes(str(username + client_id).encode("latin-1"))
new_digest = hmac.new(key, msg, hashlib.sha256).digest()
secret_hash = base64.b64encode(new_digest).decode()
result = conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": secret_hash,
},
)
# Try to log in with user in status FORCE_CHANGE_PASSWORD
result = conn.respond_to_auth_challenge(
ClientId=client_id,
ChallengeName=result["ChallengeName"],
ChallengeResponses={
"PASSWORD_CLAIM_SIGNATURE": str(uuid.uuid4()),
"PASSWORD_CLAIM_SECRET_BLOCK": result["Session"],
"TIMESTAMP": str(uuid.uuid4()),
"USERNAME": username,
},
)
assert result["ChallengeName"] == "NEW_PASSWORD_REQUIRED"
assert result["Session"] is not None
assert result["ChallengeParameters"]["USERNAME"] == username
# Sets a new password to the user and log it in
result = conn.respond_to_auth_challenge(
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
Session=result["Session"],
ChallengeResponses={
"USERNAME": username,
"NEW_PASSWORD": new_password,
},
)
assert result["AuthenticationResult"]["AccessToken"] is not None
@mock_cognitoidp
def test_set_user_pool_mfa_config():
conn = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=name)["UserPool"]["Id"]
# Test error for when neither token nor sms configuration is provided
with pytest.raises(ClientError) as ex:
conn.set_user_pool_mfa_config(UserPoolId=user_pool_id, MfaConfiguration="ON")
assert ex.value.operation_name == "SetUserPoolMfaConfig"
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "At least one of [SmsMfaConfiguration] or [SoftwareTokenMfaConfiguration] must be provided."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
# Test error for when sms config is missing `SmsConfiguration`
with pytest.raises(ClientError) as ex:
conn.set_user_pool_mfa_config(
UserPoolId=user_pool_id, SmsMfaConfiguration={}, MfaConfiguration="ON"
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "[SmsConfiguration] is a required member of [SoftwareTokenMfaConfiguration]."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
# Test error for when `SmsConfiguration` is missing `SnsCaller`
# This is asserted by boto3
with pytest.raises(ParamValidationError) as ex:
conn.set_user_pool_mfa_config(
UserPoolId=user_pool_id,
SmsMfaConfiguration={"SmsConfiguration": {}},
MfaConfiguration="ON",
)
# Test error for when `MfaConfiguration` is not one of the expected values
with pytest.raises(ClientError) as ex:
conn.set_user_pool_mfa_config(
UserPoolId=user_pool_id,
SoftwareTokenMfaConfiguration={"Enabled": True},
MfaConfiguration="Invalid",
)
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== "[MfaConfiguration] must be one of 'ON', 'OFF', or 'OPTIONAL'."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
# Enable software token MFA
mfa_config = conn.set_user_pool_mfa_config(
UserPoolId=user_pool_id,
SoftwareTokenMfaConfiguration={"Enabled": True},
MfaConfiguration="ON",
)
assert "SmsMfaConfiguration" not in mfa_config
assert mfa_config["MfaConfiguration"] == "ON"
assert mfa_config["SoftwareTokenMfaConfiguration"] == {"Enabled": True}
# Response from describe should match
pool = conn.describe_user_pool(UserPoolId=user_pool_id)["UserPool"]
assert pool["MfaConfiguration"] == "ON"
# Disable MFA
mfa_config = conn.set_user_pool_mfa_config(
UserPoolId=user_pool_id, MfaConfiguration="OFF"
)
assert "SmsMfaConfiguration" not in mfa_config
assert "SoftwareTokenMfaConfiguration" not in mfa_config
assert mfa_config["MfaConfiguration"] == "OFF"
# Response from describe should match
pool = conn.describe_user_pool(UserPoolId=user_pool_id)["UserPool"]
assert pool["MfaConfiguration"] == "OFF"
# `SnsCallerArn` needs to be at least 20 long
sms_config = {"SmsConfiguration": {"SnsCallerArn": "01234567890123456789"}}
# Enable SMS MFA
mfa_config = conn.set_user_pool_mfa_config(
UserPoolId=user_pool_id, SmsMfaConfiguration=sms_config, MfaConfiguration="ON"
)
assert "SoftwareTokenMfaConfiguration" not in mfa_config
assert mfa_config["SmsMfaConfiguration"] == sms_config
assert mfa_config["MfaConfiguration"] == "ON"
@mock_cognitoidp
def test_list_user_pools_returns_max_items():
conn = boto3.client("cognito-idp", "us-west-2")
# Given 10 user pools
pool_count = 10
for _ in range(pool_count):
conn.create_user_pool(PoolName=str(uuid.uuid4()))
max_results = 5
result = conn.list_user_pools(MaxResults=max_results)
assert len(result["UserPools"]) == max_results
assert "NextToken" in result
@mock_cognitoidp
def test_list_user_pools_returns_next_tokens():
conn = boto3.client("cognito-idp", "us-west-2")
# Given 10 user pool clients
pool_count = 10
for _ in range(pool_count):
conn.create_user_pool(PoolName=str(uuid.uuid4()))
max_results = 5
result = conn.list_user_pools(MaxResults=max_results)
assert len(result["UserPools"]) == max_results
assert "NextToken" in result
next_token = result["NextToken"]
result_2 = conn.list_user_pools(MaxResults=max_results, NextToken=next_token)
assert len(result_2["UserPools"]) == max_results
assert "NextToken" not in result_2
@mock_cognitoidp
def test_list_user_pools_when_max_items_more_than_total_items():
conn = boto3.client("cognito-idp", "us-west-2")
# Given 10 user pool clients
pool_count = 10
for _ in range(pool_count):
conn.create_user_pool(PoolName=str(uuid.uuid4()))
max_results = pool_count + 5
result = conn.list_user_pools(MaxResults=max_results)
assert len(result["UserPools"]) == pool_count
assert "NextToken" not in result
@mock_cognitoidp
def test_describe_user_pool():
conn = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
value = str(uuid.uuid4())
recovery_mechanisms = [{"Name": "verified_email", "Priority": 1}]
user_pool_details = conn.create_user_pool(
PoolName=name,
LambdaConfig={"PreSignUp": value},
AccountRecoverySetting={"RecoveryMechanisms": recovery_mechanisms},
)
result = conn.describe_user_pool(UserPoolId=user_pool_details["UserPool"]["Id"])
assert result["UserPool"]["Name"] == name
assert result["UserPool"]["LambdaConfig"]["PreSignUp"] == value
assert (
result["UserPool"]["AccountRecoverySetting"]["RecoveryMechanisms"]
== recovery_mechanisms
)
@mock_cognitoidp
def test_describe_user_pool_estimated_number_of_users():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.describe_user_pool(UserPoolId=user_pool_id)
assert result["UserPool"]["EstimatedNumberOfUsers"] == 0
users_count = random.randint(2, 6)
for _ in range(users_count):
conn.admin_create_user(UserPoolId=user_pool_id, Username=str(uuid.uuid4()))
result = conn.describe_user_pool(UserPoolId=user_pool_id)
assert result["UserPool"]["EstimatedNumberOfUsers"] == users_count
@mock_cognitoidp
def test_describe_user_pool_resource_not_found():
conn = boto3.client("cognito-idp", "us-east-1")
user_pool_id = "us-east-1_FooBar123"
with pytest.raises(ClientError) as exc:
conn.describe_user_pool(UserPoolId=user_pool_id)
err = exc.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
assert err["Message"] == f"User pool {user_pool_id} does not exist."
@mock_cognitoidp
def test_update_user_pool():
conn = boto3.client("cognito-idp", "us-east-1")
name = str(uuid.uuid4())
user_pool_details = conn.create_user_pool(
PoolName=name,
Policies={
"PasswordPolicy": {
"MinimumLength": 12,
"RequireUppercase": False,
"RequireLowercase": False,
"RequireNumbers": False,
"RequireSymbols": False,
}
},
)
new_policies = {
"PasswordPolicy": {
"MinimumLength": 16,
"RequireUppercase": True,
"RequireLowercase": True,
"RequireNumbers": True,
"RequireSymbols": True,
}
}
conn.update_user_pool(
UserPoolId=user_pool_details["UserPool"]["Id"], Policies=new_policies
)
updated_user_pool_details = conn.describe_user_pool(
UserPoolId=user_pool_details["UserPool"]["Id"]
)
assert updated_user_pool_details["UserPool"]["Policies"] == new_policies
assert updated_user_pool_details["UserPool"]["AdminCreateUserConfig"] is not None
assert updated_user_pool_details["UserPool"]["EmailConfiguration"] is not None
assert (
updated_user_pool_details["UserPool"]["VerificationMessageTemplate"] is not None
)
assert updated_user_pool_details["UserPool"]["AccountRecoverySetting"] is not None
@mock_cognitoidp
def test_delete_user_pool():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
assert len(conn.list_user_pools(MaxResults=10)["UserPools"]) == 1
conn.delete_user_pool(UserPoolId=user_pool_id)
assert len(conn.list_user_pools(MaxResults=10)["UserPools"]) == 0
@mock_cognitoidp
def test_create_user_pool_domain():
conn = boto3.client("cognito-idp", "us-west-2")
domain = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
assert result["CloudFrontDomain"] is not None
@mock_cognitoidp
def test_create_user_pool_domain_custom_domain_config():
conn = boto3.client("cognito-idp", "us-west-2")
domain = str(uuid.uuid4())
custom_domain_config = {
"CertificateArn": f"arn:aws:acm:us-east-1:{ACCOUNT_ID}:certificate/123456789012"
}
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.create_user_pool_domain(
UserPoolId=user_pool_id, Domain=domain, CustomDomainConfig=custom_domain_config
)
assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
assert result["CloudFrontDomain"] == "e2c343b3293ee505.cloudfront.net"
@mock_cognitoidp
def test_describe_user_pool_domain():
conn = boto3.client("cognito-idp", "us-west-2")
domain = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
result = conn.describe_user_pool_domain(Domain=domain)
assert result["DomainDescription"]["Domain"] == domain
assert result["DomainDescription"]["UserPoolId"] == user_pool_id
assert result["DomainDescription"]["AWSAccountId"] is not None
result = conn.describe_user_pool(UserPoolId=user_pool_id)
assert result["UserPool"]["Domain"] == domain
@mock_cognitoidp
def test_delete_user_pool_domain():
conn = boto3.client("cognito-idp", "us-west-2")
domain = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
result = conn.delete_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
result = conn.describe_user_pool_domain(Domain=domain)
# This is a surprising behavior of the real service: describing a missing domain comes
# back with status 200 and a DomainDescription of {}
assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
assert len(result["DomainDescription"].keys()) == 0
@mock_cognitoidp
def test_update_user_pool_domain():
conn = boto3.client("cognito-idp", "us-west-2")
domain = str(uuid.uuid4())
custom_domain_config = {
"CertificateArn": f"arn:aws:acm:us-east-1:{ACCOUNT_ID}:certificate/123456789012"
}
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
result = conn.update_user_pool_domain(
UserPoolId=user_pool_id, Domain=domain, CustomDomainConfig=custom_domain_config
)
assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
assert result["CloudFrontDomain"] == "e2c343b3293ee505.cloudfront.net"
@mock_cognitoidp
def test_create_user_pool_client():
conn = boto3.client("cognito-idp", "us-west-2")
client_name = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=client_name, CallbackURLs=[value]
)
assert result["UserPoolClient"]["UserPoolId"] == user_pool_id
assert bool(re.match(r"^[0-9a-z]{26}$", result["UserPoolClient"]["ClientId"]))
assert result["UserPoolClient"]["ClientName"] == client_name
assert "ClientSecret" not in result["UserPoolClient"]
assert len(result["UserPoolClient"]["CallbackURLs"]) == 1
assert result["UserPoolClient"]["CallbackURLs"][0] == value
@mock_cognitoidp
def test_create_user_pool_client_returns_secret():
conn = boto3.client("cognito-idp", "us-west-2")
client_name = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=client_name,
GenerateSecret=True,
CallbackURLs=[value],
)
assert result["UserPoolClient"]["UserPoolId"] == user_pool_id
assert bool(re.match(r"^[0-9a-z]{26}$", result["UserPoolClient"]["ClientId"]))
assert result["UserPoolClient"]["ClientName"] == client_name
assert result["UserPoolClient"]["ClientSecret"] is not None
assert len(result["UserPoolClient"]["CallbackURLs"]) == 1
assert result["UserPoolClient"]["CallbackURLs"][0] == value
@mock_cognitoidp
def test_list_user_pool_clients():
conn = boto3.client("cognito-idp", "us-west-2")
client_name = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_user_pool_client(UserPoolId=user_pool_id, ClientName=client_name)
result = conn.list_user_pool_clients(UserPoolId=user_pool_id, MaxResults=10)
assert len(result["UserPoolClients"]) == 1
assert result["UserPoolClients"][0]["ClientName"] == client_name
@mock_cognitoidp
def test_list_user_pool_clients_returns_max_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 user pool clients
client_count = 10
for _ in range(client_count):
client_name = str(uuid.uuid4())
conn.create_user_pool_client(UserPoolId=user_pool_id, ClientName=client_name)
max_results = 5
result = conn.list_user_pool_clients(
UserPoolId=user_pool_id, MaxResults=max_results
)
assert len(result["UserPoolClients"]) == max_results
assert "NextToken" in result
@mock_cognitoidp
def test_list_user_pool_clients_returns_next_tokens():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 user pool clients
client_count = 10
for _ in range(client_count):
client_name = str(uuid.uuid4())
conn.create_user_pool_client(UserPoolId=user_pool_id, ClientName=client_name)
max_results = 5
result = conn.list_user_pool_clients(
UserPoolId=user_pool_id, MaxResults=max_results
)
assert len(result["UserPoolClients"]) == max_results
assert "NextToken" in result
next_token = result["NextToken"]
result_2 = conn.list_user_pool_clients(
UserPoolId=user_pool_id, MaxResults=max_results, NextToken=next_token
)
assert len(result_2["UserPoolClients"]) == max_results
assert "NextToken" not in result_2
@mock_cognitoidp
def test_list_user_pool_clients_when_max_items_more_than_total_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 user pool clients
client_count = 10
for _ in range(client_count):
client_name = str(uuid.uuid4())
conn.create_user_pool_client(UserPoolId=user_pool_id, ClientName=client_name)
max_results = client_count + 5
result = conn.list_user_pool_clients(
UserPoolId=user_pool_id, MaxResults=max_results
)
assert len(result["UserPoolClients"]) == client_count
assert "NextToken" not in result
@mock_cognitoidp
def test_describe_user_pool_client():
conn = boto3.client("cognito-idp", "us-west-2")
client_name = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_details = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=client_name, CallbackURLs=[value]
)
result = conn.describe_user_pool_client(
UserPoolId=user_pool_id, ClientId=client_details["UserPoolClient"]["ClientId"]
)
assert result["UserPoolClient"]["ClientName"] == client_name
assert len(result["UserPoolClient"]["CallbackURLs"]) == 1
assert result["UserPoolClient"]["CallbackURLs"][0] == value
@mock_cognitoidp
def test_update_user_pool_client():
conn = boto3.client("cognito-idp", "us-west-2")
old_client_name = str(uuid.uuid4())
new_client_name = str(uuid.uuid4())
old_value = str(uuid.uuid4())
new_value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_details = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=old_client_name, CallbackURLs=[old_value]
)
result = conn.update_user_pool_client(
UserPoolId=user_pool_id,
ClientId=client_details["UserPoolClient"]["ClientId"],
ClientName=new_client_name,
CallbackURLs=[new_value],
)
assert result["UserPoolClient"]["ClientName"] == new_client_name
assert "ClientSecret" not in result["UserPoolClient"]
assert len(result["UserPoolClient"]["CallbackURLs"]) == 1
assert result["UserPoolClient"]["CallbackURLs"][0] == new_value
@mock_cognitoidp
def test_update_user_pool_client_returns_secret():
conn = boto3.client("cognito-idp", "us-west-2")
old_client_name = str(uuid.uuid4())
new_client_name = str(uuid.uuid4())
old_value = str(uuid.uuid4())
new_value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_details = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=old_client_name,
GenerateSecret=True,
CallbackURLs=[old_value],
)
client_secret = client_details["UserPoolClient"]["ClientSecret"]
result = conn.update_user_pool_client(
UserPoolId=user_pool_id,
ClientId=client_details["UserPoolClient"]["ClientId"],
ClientName=new_client_name,
CallbackURLs=[new_value],
)
assert result["UserPoolClient"]["ClientName"] == new_client_name
assert result["UserPoolClient"]["ClientSecret"] == client_secret
assert len(result["UserPoolClient"]["CallbackURLs"]) == 1
assert result["UserPoolClient"]["CallbackURLs"][0] == new_value
@mock_cognitoidp
def test_delete_user_pool_client():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_details = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)
conn.delete_user_pool_client(
UserPoolId=user_pool_id, ClientId=client_details["UserPoolClient"]["ClientId"]
)
with pytest.raises(ClientError) as exc:
conn.describe_user_pool_client(
UserPoolId=user_pool_id,
ClientId=client_details["UserPoolClient"]["ClientId"],
)
err = exc.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
@mock_cognitoidp
def test_create_identity_provider():
conn = boto3.client("cognito-idp", "us-west-2")
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={"thing": value},
)
assert result["IdentityProvider"]["UserPoolId"] == user_pool_id
assert result["IdentityProvider"]["ProviderName"] == provider_name
assert result["IdentityProvider"]["ProviderType"] == provider_type
assert result["IdentityProvider"]["ProviderDetails"]["thing"] == value
@mock_cognitoidp
def test_list_identity_providers():
conn = boto3.client("cognito-idp", "us-west-2")
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={},
)
result = conn.list_identity_providers(UserPoolId=user_pool_id, MaxResults=10)
assert len(result["Providers"]) == 1
assert result["Providers"][0]["ProviderName"] == provider_name
assert result["Providers"][0]["ProviderType"] == provider_type
@mock_cognitoidp
def test_list_identity_providers_returns_max_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 identity providers linked to a user pool
identity_provider_count = 10
for _ in range(identity_provider_count):
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={},
)
max_results = 5
result = conn.list_identity_providers(
UserPoolId=user_pool_id, MaxResults=max_results
)
assert len(result["Providers"]) == max_results
assert "NextToken" in result
@mock_cognitoidp
def test_list_identity_providers_returns_next_tokens():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 identity providers linked to a user pool
identity_provider_count = 10
for _ in range(identity_provider_count):
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={},
)
max_results = 5
result = conn.list_identity_providers(
UserPoolId=user_pool_id, MaxResults=max_results
)
assert len(result["Providers"]) == max_results
assert "NextToken" in result
next_token = result["NextToken"]
result_2 = conn.list_identity_providers(
UserPoolId=user_pool_id, MaxResults=max_results, NextToken=next_token
)
assert len(result_2["Providers"]) == max_results
assert "NextToken" not in result_2
@mock_cognitoidp
def test_list_identity_providers_when_max_items_more_than_total_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 identity providers linked to a user pool
identity_provider_count = 10
for _ in range(identity_provider_count):
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={},
)
max_results = identity_provider_count + 5
result = conn.list_identity_providers(
UserPoolId=user_pool_id, MaxResults=max_results
)
assert len(result["Providers"]) == identity_provider_count
assert "NextToken" not in result
@mock_cognitoidp
def test_describe_identity_providers():
conn = boto3.client("cognito-idp", "us-west-2")
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={"thing": value},
)
result = conn.describe_identity_provider(
UserPoolId=user_pool_id, ProviderName=provider_name
)
assert result["IdentityProvider"]["UserPoolId"] == user_pool_id
assert result["IdentityProvider"]["ProviderName"] == provider_name
assert result["IdentityProvider"]["ProviderType"] == provider_type
assert result["IdentityProvider"]["ProviderDetails"]["thing"] == value
@mock_cognitoidp
def test_update_identity_provider():
conn = boto3.client("cognito-idp", "us-west-2")
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
value = str(uuid.uuid4())
new_value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={"thing": value},
)
result = conn.update_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderDetails={"thing": new_value},
AttributeMapping={"email": "email", "username": "sub"},
)["IdentityProvider"]
assert result["UserPoolId"] == user_pool_id
assert result["ProviderName"] == provider_name
assert result["ProviderType"] == provider_type
assert result["ProviderDetails"]["thing"] == new_value
assert result["AttributeMapping"] == {"email": "email", "username": "sub"}
@mock_cognitoidp
def test_update_identity_provider_no_user_pool():
conn = boto3.client("cognito-idp", "us-west-2")
new_value = str(uuid.uuid4())
with pytest.raises(conn.exceptions.ResourceNotFoundException) as cm:
conn.update_identity_provider(
UserPoolId="foo", ProviderName="bar", ProviderDetails={"thing": new_value}
)
assert cm.value.operation_name == "UpdateIdentityProvider"
assert cm.value.response["Error"]["Code"] == "ResourceNotFoundException"
assert cm.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_update_identity_provider_no_identity_provider():
conn = boto3.client("cognito-idp", "us-west-2")
new_value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
with pytest.raises(conn.exceptions.ResourceNotFoundException) as cm:
conn.update_identity_provider(
UserPoolId=user_pool_id,
ProviderName="foo",
ProviderDetails={"thing": new_value},
)
assert cm.value.operation_name == "UpdateIdentityProvider"
assert cm.value.response["Error"]["Code"] == "ResourceNotFoundException"
assert cm.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_delete_identity_providers():
conn = boto3.client("cognito-idp", "us-west-2")
provider_name = str(uuid.uuid4())
provider_type = "Facebook"
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.create_identity_provider(
UserPoolId=user_pool_id,
ProviderName=provider_name,
ProviderType=provider_type,
ProviderDetails={"thing": value},
)
conn.delete_identity_provider(UserPoolId=user_pool_id, ProviderName=provider_name)
with pytest.raises(ClientError) as exc:
conn.describe_identity_provider(
UserPoolId=user_pool_id, ProviderName=provider_name
)
err = exc.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
@mock_cognitoidp
def test_create_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
description = str(uuid.uuid4())
role_arn = "arn:aws:iam:::role/my-iam-role"
precedence = random.randint(0, 100000)
result = conn.create_group(
GroupName=group_name,
UserPoolId=user_pool_id,
Description=description,
RoleArn=role_arn,
Precedence=precedence,
)
assert result["Group"]["GroupName"] == group_name
assert result["Group"]["UserPoolId"] == user_pool_id
assert result["Group"]["Description"] == description
assert result["Group"]["RoleArn"] == role_arn
assert result["Group"]["Precedence"] == precedence
assert isinstance(result["Group"]["LastModifiedDate"], datetime.datetime)
assert isinstance(result["Group"]["CreationDate"], datetime.datetime)
@mock_cognitoidp
def test_update_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
description = str(uuid.uuid4())
description2 = str(uuid.uuid4())
role_arn = "arn:aws:iam:::role/my-iam-role"
role_arn2 = "arn:aws:iam:::role/my-iam-role2"
precedence = random.randint(0, 100000)
precedence2 = random.randint(0, 100000)
conn.create_group(
GroupName=group_name,
UserPoolId=user_pool_id,
Description=description,
RoleArn=role_arn,
Precedence=precedence,
)
result = conn.update_group(
GroupName=group_name,
UserPoolId=user_pool_id,
Description=description2,
RoleArn=role_arn2,
Precedence=precedence2,
)
assert result["Group"]["GroupName"] == group_name
assert result["Group"]["UserPoolId"] == user_pool_id
assert result["Group"]["Description"] == description2
assert result["Group"]["RoleArn"] == role_arn2
assert result["Group"]["Precedence"] == precedence2
assert isinstance(result["Group"]["LastModifiedDate"], datetime.datetime)
assert isinstance(result["Group"]["CreationDate"], datetime.datetime)
@mock_cognitoidp
def test_group_in_access_token():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
temporary_password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
user_attribute_name = str(uuid.uuid4())
user_attribute_value = str(uuid.uuid4())
group_name = str(uuid.uuid4())
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=str(uuid.uuid4()),
ReadAttributes=[user_attribute_name],
)["UserPoolClient"]["ClientId"]
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
TemporaryPassword=temporary_password,
UserAttributes=[{"Name": user_attribute_name, "Value": user_attribute_value}],
)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
result = conn.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
# A newly created user is forced to set a new password
assert result["ChallengeName"] == "NEW_PASSWORD_REQUIRED"
assert result["Session"] is not None
# This sets a new password and logs the user in (creates tokens)
new_password = "P2$Sword"
result = conn.admin_respond_to_auth_challenge(
UserPoolId=user_pool_id,
Session=result["Session"],
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
)
claims = jwt.get_unverified_claims(result["AuthenticationResult"]["AccessToken"])
assert claims["cognito:groups"] == [group_name]
@mock_cognitoidp
def test_other_attributes_in_id_token():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
temporary_password = "P2$Sword"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[{"Name": "myattr", "AttributeDataType": "String"}],
)["UserPool"]["Id"]
user_attribute_name = str(uuid.uuid4())
user_attribute_value = str(uuid.uuid4())
group_name = str(uuid.uuid4())
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=str(uuid.uuid4()),
ReadAttributes=[user_attribute_name],
)["UserPoolClient"]["ClientId"]
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
TemporaryPassword=temporary_password,
UserAttributes=[
{"Name": user_attribute_name, "Value": user_attribute_value},
{"Name": "custom:myattr", "Value": "some val"},
],
)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
result = conn.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
# A newly created user is forced to set a new password
assert result["ChallengeName"] == "NEW_PASSWORD_REQUIRED"
assert result["Session"] is not None
# This sets a new password and logs the user in (creates tokens)
new_password = "P2$Sword"
result = conn.admin_respond_to_auth_challenge(
UserPoolId=user_pool_id,
Session=result["Session"],
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
)
claims = jwt.get_unverified_claims(result["AuthenticationResult"]["IdToken"])
assert claims["cognito:groups"] == [group_name]
assert claims["custom:myattr"] == "some val"
@mock_cognitoidp
def test_create_group_with_duplicate_name_raises_error():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
with pytest.raises(ClientError) as cm:
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
assert cm.value.operation_name == "CreateGroup"
assert cm.value.response["Error"]["Code"] == "GroupExistsException"
assert cm.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_get_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
result = conn.get_group(GroupName=group_name, UserPoolId=user_pool_id)
assert result["Group"]["GroupName"] == group_name
assert result["Group"]["UserPoolId"] == user_pool_id
assert isinstance(result["Group"]["LastModifiedDate"], datetime.datetime)
assert isinstance(result["Group"]["CreationDate"], datetime.datetime)
@mock_cognitoidp
def test_list_groups():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
result = conn.list_groups(UserPoolId=user_pool_id)
assert len(result["Groups"]) == 1
assert result["Groups"][0]["GroupName"] == group_name
@mock_cognitoidp
def test_list_groups_returns_pagination_tokens():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 groups
group_count = 10
for _ in range(group_count):
conn.create_group(UserPoolId=user_pool_id, GroupName=str(uuid.uuid4()))
max_results = 5
result = conn.list_groups(UserPoolId=user_pool_id, Limit=max_results)
assert len(result["Groups"]) == max_results
assert "NextToken" in result
next_token = result["NextToken"]
result_2 = conn.list_groups(
UserPoolId=user_pool_id, Limit=max_results, NextToken=next_token
)
assert len(result_2["Groups"]) == max_results
assert "NextToken" not in result_2
@mock_cognitoidp
def test_list_groups_when_limit_more_than_total_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 users
group_count = 10
for _ in range(group_count):
conn.create_group(UserPoolId=user_pool_id, GroupName=str(uuid.uuid4()))
max_results = group_count + 5
result = conn.list_groups(UserPoolId=user_pool_id, Limit=max_results)
assert len(result["Groups"]) == group_count
assert "NextToken" not in result
@mock_cognitoidp
def test_delete_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
result = conn.delete_group(GroupName=group_name, UserPoolId=user_pool_id)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
with pytest.raises(ClientError) as cm:
conn.get_group(GroupName=group_name, UserPoolId=user_pool_id)
assert cm.value.response["Error"]["Code"] == "ResourceNotFoundException"
@mock_cognitoidp
def test_admin_add_user_to_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
@mock_cognitoidp
def test_admin_add_user_to_group_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = "test@example.com"
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
@mock_cognitoidp
def test_admin_add_user_to_group_again_is_noop():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
@mock_cognitoidp
def test_list_users_in_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
result = conn.list_users_in_group(UserPoolId=user_pool_id, GroupName=group_name)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == username
@mock_cognitoidp
def test_list_users_in_group_ignores_deleted_user():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
username2 = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username2)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username2, GroupName=group_name
)
conn.admin_delete_user(UserPoolId=user_pool_id, Username=username)
result = conn.list_users_in_group(UserPoolId=user_pool_id, GroupName=group_name)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == username2
@mock_cognitoidp
def test_list_users_in_group_returns_pagination_tokens():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
# Given 10 users
usernames = [str(uuid.uuid4()) for _ in range(10)]
for username in usernames:
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
max_results = 5
result = conn.list_users_in_group(
UserPoolId=user_pool_id, GroupName=group_name, Limit=max_results
)
assert len(result["Users"]) == max_results
assert "NextToken" in result
next_token = result["NextToken"]
result_2 = conn.list_users_in_group(
UserPoolId=user_pool_id,
GroupName=group_name,
Limit=max_results,
NextToken=next_token,
)
assert len(result_2["Users"]) == max_results
assert "NextToken" not in result_2
@mock_cognitoidp
def test_list_users_in_group_when_limit_more_than_total_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
# Given 10 users
usernames = [str(uuid.uuid4()) for _ in range(10)]
for username in usernames:
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
max_results = len(usernames) + 5
result = conn.list_users_in_group(
UserPoolId=user_pool_id, GroupName=group_name, Limit=max_results
)
assert len(result["Users"]) == len(usernames)
assert "NextToken" not in result
@mock_cognitoidp
def test_admin_list_groups_for_user():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
result = conn.admin_list_groups_for_user(Username=username, UserPoolId=user_pool_id)
assert len(result["Groups"]) == 1
assert result["Groups"][0]["GroupName"] == group_name
@mock_cognitoidp
def test_admin_list_groups_for_user_with_username_attribute():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = "test@example.com"
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
result = conn.admin_list_groups_for_user(Username=username, UserPoolId=user_pool_id)
assert len(result["Groups"]) == 1
assert result["Groups"][0]["GroupName"] == group_name
@mock_cognitoidp
def test_admin_list_groups_for_user_ignores_deleted_group():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
group_name2 = str(uuid.uuid4())
conn.create_group(GroupName=group_name2, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name2
)
conn.delete_group(GroupName=group_name, UserPoolId=user_pool_id)
result = conn.admin_list_groups_for_user(Username=username, UserPoolId=user_pool_id)
assert len(result["Groups"]) == 1
assert result["Groups"][0]["GroupName"] == group_name2
@mock_cognitoidp
def test_admin_remove_user_from_group():
conn = boto3.client("cognito-idp", "us-west-2")
pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=pool_id)
uname = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=pool_id, Username=uname)
conn.admin_add_user_to_group(
UserPoolId=pool_id, Username=uname, GroupName=group_name
)
result = conn.admin_remove_user_from_group(
UserPoolId=pool_id, Username=uname, GroupName=group_name
)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
resp = conn.list_users_in_group(UserPoolId=pool_id, GroupName=group_name)
assert resp["Users"] == []
resp = conn.admin_list_groups_for_user(Username=uname, UserPoolId=pool_id)
assert resp["Groups"] == []
@mock_cognitoidp
def test_admin_remove_user_from_group_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=pool_id)
uname = "test@example.com"
conn.admin_create_user(UserPoolId=pool_id, Username=uname)
conn.admin_add_user_to_group(
UserPoolId=pool_id, Username=uname, GroupName=group_name
)
result = conn.admin_remove_user_from_group(
UserPoolId=pool_id, Username=uname, GroupName=group_name
)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
resp = conn.list_users_in_group(UserPoolId=pool_id, GroupName=group_name)
assert resp["Users"] == []
resp = conn.admin_list_groups_for_user(Username=uname, UserPoolId=pool_id)
assert resp["Groups"] == []
@mock_cognitoidp
def test_admin_remove_user_from_group_again_is_noop():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
group_name = str(uuid.uuid4())
conn.create_group(GroupName=group_name, UserPoolId=user_pool_id)
username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
conn.admin_add_user_to_group(
UserPoolId=user_pool_id, Username=username, GroupName=group_name
)
@mock_cognitoidp
def test_admin_create_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
result = conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
assert result["User"]["Username"] == username
assert result["User"]["UserStatus"] == "FORCE_CHANGE_PASSWORD"
assert len(result["User"]["Attributes"]) == 2
def _verify_attribute(name, v):
attr = [a for a in result["User"]["Attributes"] if a["Name"] == name]
assert len(attr) == 1
assert attr[0]["Value"] == v
_verify_attribute("thing", value)
assert result["User"]["Enabled"] is True
@mock_cognitoidp
def test_admin_create_user_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
result = conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
assert result["User"]["Username"] != username
assert result["User"]["UserStatus"] == "FORCE_CHANGE_PASSWORD"
assert len(result["User"]["Attributes"]) == 3
def _verify_attribute(name, v):
attr = [a for a in result["User"]["Attributes"] if a["Name"] == name]
assert len(attr) == 1
assert attr[0]["Value"] == v
_verify_attribute("thing", value)
_verify_attribute("email", username)
assert result["User"]["Enabled"] is True
@mock_cognitoidp
def test_admin_create_user_with_incorrect_username_attribute_type_fails():
conn = boto3.client("cognito-idp", "us-west-2")
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
with pytest.raises(ClientError) as ex:
username = str(uuid.uuid4())
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
err = ex.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert err["Message"] == "Username should be either an email or a phone number."
@mock_cognitoidp
def test_admin_create_user_with_existing_username_attribute_fails():
conn = boto3.client("cognito-idp", "us-west-2")
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
username = "test@example.com"
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
with pytest.raises(ClientError) as ex:
username = "test@example.com"
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
err = ex.value.response["Error"]
assert err["Code"] == "UsernameExistsException"
assert err["Message"] == "test@example.com"
@mock_cognitoidp
def test_admin_create_existing_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
with pytest.raises(ClientError) as exc:
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
err = exc.value.response["Error"]
assert err["Code"] == "UsernameExistsException"
@mock_cognitoidp
def test_admin_confirm_sign_up():
conn = boto3.client("cognito-idp", "us-east-1")
username = str(uuid.uuid4())
password = "Passw0rd!"
user_pool_id = conn.create_user_pool(
PoolName="us-east-1_aaaaaaaa", AutoVerifiedAttributes=["email"]
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=False
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
user = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert user["UserStatus"] == "UNCONFIRMED"
conn.admin_confirm_sign_up(UserPoolId=user_pool_id, Username=username)
user = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert user["UserStatus"] == "CONFIRMED"
@mock_cognitoidp
def test_admin_confirm_sign_up_non_existing_user():
conn = boto3.client("cognito-idp", "us-east-1")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName="us-east-1_aaaaaaaa", AutoVerifiedAttributes=["email"]
)["UserPool"]["Id"]
with pytest.raises(ClientError) as exc:
conn.admin_confirm_sign_up(UserPoolId=user_pool_id, Username=username)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
assert err["Message"] == "User does not exist."
@mock_cognitoidp
def test_admin_confirm_sign_up_non_existing_pool():
conn = boto3.client("cognito-idp", "us-east-1")
user_pool_id = "us-east-1_aaaaaaaa"
with pytest.raises(ClientError) as exc:
conn.admin_confirm_sign_up(UserPoolId=user_pool_id, Username=str(uuid.uuid4()))
err = exc.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
assert err["Message"] == f"User pool {user_pool_id} does not exist."
@mock_cognitoidp
def test_admin_resend_invitation_existing_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
# Resending this should not throw an error
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
MessageAction="RESEND",
)
@mock_cognitoidp
def test_admin_resend_invitation_missing_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
with pytest.raises(ClientError) as exc:
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
MessageAction="RESEND",
)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
assert err["Message"] == "User does not exist."
@mock_cognitoidp
def test_admin_get_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert result["Username"] == username
assert len(result["UserAttributes"]) == 2
@mock_cognitoidp
def test_admin_get_user_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email", "phone_number"]
)["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[
{"Name": "thing", "Value": value},
{"Name": "phone_number", "Value": "+123456789"},
],
)
# verify user can be queried by email
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert result["Username"] != username
assert len(result["UserAttributes"]) == 4
def _verify_attribute(name, v):
attr = [a for a in result["UserAttributes"] if a["Name"] == name]
assert len(attr) == 1
assert attr[0]["Value"] == v
_verify_attribute("phone_number", "+123456789")
_verify_attribute("email", "test@example.com")
# verify user can be queried by phone number
result = conn.admin_get_user(UserPoolId=user_pool_id, Username="+123456789")
assert result["Username"] != username
assert len(result["UserAttributes"]) == 4
_verify_attribute("phone_number", "+123456789")
_verify_attribute("email", "test@example.com")
# verify that the generate user sub is a valid UUID v4
[user_sub] = [
attr["Value"] for attr in result["UserAttributes"] if attr["Name"] == "sub"
]
uuid.UUID(user_sub)
# verify user should be queried by user sub
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=user_sub)
assert result["Username"] != username
assert len(result["UserAttributes"]) == 4
_verify_attribute("phone_number", "+123456789")
_verify_attribute("email", "test@example.com")
@mock_cognitoidp
def test_admin_get_missing_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
with pytest.raises(ClientError) as exc:
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
assert err["Message"] == "User does not exist."
@mock_cognitoidp
def test_admin_get_missing_user_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
with pytest.raises(ClientError) as exc:
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
assert err["Message"] == "User does not exist."
@mock_cognitoidp
def test_get_user():
conn = boto3.client("cognito-idp", "us-west-2")
outputs = authentication_flow(conn, "ADMIN_NO_SRP_AUTH")
result = conn.get_user(AccessToken=outputs["access_token"])
assert result["Username"] == outputs["username"]
assert len(result["UserAttributes"]) == 2
def _verify_attribute(name, v):
attr = [a for a in result["UserAttributes"] if a["Name"] == name]
assert len(attr) == 1
assert attr[0]["Value"] == v
for key, value in outputs["additional_fields"].items():
_verify_attribute(key, value)
@mock_cognitoidp
def test_get_user_unknown_accesstoken():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.get_user(AccessToken="n/a")
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "Invalid token"
@mock_cognitoidp
def test_list_users():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.list_users(UserPoolId=user_pool_id)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == username
username_bis = str(uuid.uuid4())
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username_bis,
UserAttributes=[{"Name": "phone_number", "Value": "+33666666666"}],
)
result = conn.list_users(
UserPoolId=user_pool_id, Filter='phone_number="+33666666666"'
)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == username_bis
# checking Filter with space
result = conn.list_users(
UserPoolId=user_pool_id, Filter='phone_number = "+33666666666"'
)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == 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"')
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == user0_username
# empty value Filter should also be supported
result = conn.list_users(UserPoolId=user_pool_id, Filter='family_name=""')
assert len(result["Users"]) == 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"] == "InvalidParameterException"
assert err["Message"] == "Error while parsing filter"
@mock_cognitoidp
def test_list_users_invalid_attributes():
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='custom:foo = "bar"')
err = exc.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert err["Message"] == "Invalid search attribute: custom:foo"
@mock_cognitoidp
def test_list_users_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.list_users(UserPoolId=user_pool_id)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] != username
def _verify_attribute(name, v):
attr = [a for a in result["Users"][0]["Attributes"] if a["Name"] == name]
assert len(attr) == 1
assert attr[0]["Value"] == v
_verify_attribute("email", username)
username_bis = "test2@uexample.com"
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username_bis,
UserAttributes=[{"Name": "phone_number", "Value": "+33666666666"}],
)
result = conn.list_users(
UserPoolId=user_pool_id, Filter='phone_number="+33666666666"'
)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] != username_bis
uuid.UUID(result["Users"][0]["Username"])
_verify_attribute("email", username_bis)
# checking Filter with space
result = conn.list_users(
UserPoolId=user_pool_id, Filter='phone_number = "+33666666666"'
)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] != username_bis
_verify_attribute("email", username_bis)
@mock_cognitoidp
def test_list_users_inherent_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.list_users(UserPoolId=user_pool_id)
assert len(result["Users"]) == 1
assert result["Users"][0]["Username"] == username
# create a confirmed disabled user
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
disabled_user_username = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=disabled_user_username)
conn.confirm_sign_up(
ClientId=client_id, Username=disabled_user_username, ConfirmationCode="123456"
)
conn.admin_disable_user(UserPoolId=user_pool_id, Username=disabled_user_username)
# filter, filter value, response field, response field expected value - all target confirmed disabled user
filters = [
("username", disabled_user_username, "Username", disabled_user_username),
("status", "Disabled", "Enabled", False),
("cognito:user_status", "CONFIRMED", "UserStatus", "CONFIRMED"),
]
for name, filter_value, response_field, response_field_expected_value in filters:
result = conn.list_users(
UserPoolId=user_pool_id, Filter=f'{name}="{filter_value}"'
)
assert len(result["Users"]) == 1
assert result["Users"][0][response_field] == response_field_expected_value
@mock_cognitoidp
def test_get_user_unconfirmed():
if settings.TEST_SERVER_MODE:
raise SkipTest("Cant patch attributes in server mode.")
conn = boto3.client("cognito-idp", "us-west-2")
outputs = authentication_flow(conn, "ADMIN_NO_SRP_AUTH")
backend = moto.cognitoidp.models.cognitoidp_backends[ACCOUNT_ID]["us-west-2"]
user_pool = backend.user_pools[outputs["user_pool_id"]]
user_pool.users[outputs["username"]].status = "UNCONFIRMED"
with pytest.raises(ClientError) as ex:
conn.get_user(AccessToken=outputs["access_token"])
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "username"
@mock_cognitoidp
def test_list_users_returns_limit_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 users
user_count = 10
for _ in range(user_count):
conn.admin_create_user(UserPoolId=user_pool_id, Username=str(uuid.uuid4()))
max_results = 5
result = conn.list_users(UserPoolId=user_pool_id, Limit=max_results)
assert len(result["Users"]) == max_results
assert "PaginationToken" in result
@mock_cognitoidp
def test_list_users_returns_pagination_tokens():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 users
user_count = 10
for _ in range(user_count):
conn.admin_create_user(UserPoolId=user_pool_id, Username=str(uuid.uuid4()))
max_results = 5
result = conn.list_users(UserPoolId=user_pool_id, Limit=max_results)
assert len(result["Users"]) == max_results
assert "PaginationToken" in result
next_token = result["PaginationToken"]
result_2 = conn.list_users(
UserPoolId=user_pool_id, Limit=max_results, PaginationToken=next_token
)
assert len(result_2["Users"]) == max_results
assert "PaginationToken" not in result_2
@mock_cognitoidp
def test_list_users_when_limit_more_than_total_items():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Given 10 users
user_count = 10
for _ in range(user_count):
conn.admin_create_user(UserPoolId=user_pool_id, Username=str(uuid.uuid4()))
max_results = user_count + 5
result = conn.list_users(UserPoolId=user_pool_id, Limit=max_results)
assert len(result["Users"]) == user_count
assert "PaginationToken" not in result
@mock_cognitoidp
def test_list_users_with_attributes_to_get():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
for _ in range(5):
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=str(uuid.uuid4()),
UserAttributes=[
{"Name": "family_name", "Value": "Doe"},
{"Name": "given_name", "Value": "Jane"},
{"Name": "custom:foo", "Value": "bar"},
],
)
result = conn.list_users(
UserPoolId=user_pool_id, AttributesToGet=["given_name", "custom:foo", "unknown"]
)
users = result["Users"]
assert len(users) == 5
for user in users:
assert len(user["Attributes"]) == 2
assert {"Name": "given_name", "Value": "Jane"} in user["Attributes"]
assert {"Name": "custom:foo", "Value": "bar"} in user["Attributes"]
@mock_cognitoidp
def test_admin_disable_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.admin_disable_user(UserPoolId=user_pool_id, Username=username)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
assert (
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)["Enabled"]
is False
)
@mock_cognitoidp
def test_admin_disable_user_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
result = conn.admin_disable_user(UserPoolId=user_pool_id, Username=username)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
assert (
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)["Enabled"]
is False
)
@mock_cognitoidp
def test_admin_enable_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_disable_user(UserPoolId=user_pool_id, Username=username)
result = conn.admin_enable_user(UserPoolId=user_pool_id, Username=username)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
assert conn.admin_get_user(UserPoolId=user_pool_id, Username=username)["Enabled"]
@mock_cognitoidp
def test_admin_enable_user_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_disable_user(UserPoolId=user_pool_id, Username=username)
result = conn.admin_enable_user(UserPoolId=user_pool_id, Username=username)
assert list(result.keys()) == ["ResponseMetadata"] # No response expected
assert conn.admin_get_user(UserPoolId=user_pool_id, Username=username)["Enabled"]
@mock_cognitoidp
def test_admin_delete_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_delete_user(UserPoolId=user_pool_id, Username=username)
with pytest.raises(ClientError) as exc:
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
@mock_cognitoidp
def test_admin_delete_user_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
conn.admin_delete_user(UserPoolId=user_pool_id, Username=username)
with pytest.raises(ClientError) as ex:
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
err = ex.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
def authentication_flow(conn, auth_flow):
username = str(uuid.uuid4())
temporary_password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
user_attribute_name = str(uuid.uuid4())
user_attribute_value = str(uuid.uuid4())
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=str(uuid.uuid4()),
ReadAttributes=[user_attribute_name],
)["UserPoolClient"]["ClientId"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
TemporaryPassword=temporary_password,
UserAttributes=[{"Name": user_attribute_name, "Value": user_attribute_value}],
)
result = conn.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow=auth_flow,
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
# A newly created user is forced to set a new password
assert result["ChallengeName"] == "NEW_PASSWORD_REQUIRED"
assert result["Session"] is not None
# This sets a new password and logs the user in (creates tokens)
new_password = "P2$Sword"
result = conn.admin_respond_to_auth_challenge(
UserPoolId=user_pool_id,
Session=result["Session"],
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
)
assert result["AuthenticationResult"]["IdToken"] is not None
assert result["AuthenticationResult"]["AccessToken"] is not None
return {
"user_pool_id": user_pool_id,
"client_id": client_id,
"id_token": result["AuthenticationResult"]["IdToken"],
"access_token": result["AuthenticationResult"]["AccessToken"],
"username": username,
"password": new_password,
"additional_fields": {user_attribute_name: user_attribute_value},
}
@mock_cognitoidp
def test_authentication_flow():
conn = boto3.client("cognito-idp", "us-west-2")
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
authentication_flow(conn, auth_flow)
@mock_cognitoidp
def test_authentication_flow_invalid_flow():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
authentication_flow(conn, "NO_SUCH_FLOW")
err = ex.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert (
err["Message"]
== "1 validation error detected: Value 'NO_SUCH_FLOW' at 'authFlow' failed to satisfy constraint: Member must satisfy enum value set: ['ADMIN_NO_SRP_AUTH', 'ADMIN_USER_PASSWORD_AUTH', 'USER_SRP_AUTH', 'REFRESH_TOKEN_AUTH', 'REFRESH_TOKEN', 'CUSTOM_AUTH', 'USER_PASSWORD_AUTH']"
)
@mock_cognitoidp
def test_authentication_flow_invalid_user_flow():
"""Pass a user authFlow to admin_initiate_auth"""
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
authentication_flow(conn, "USER_PASSWORD_AUTH")
err = ex.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert err["Message"] == "Initiate Auth method not supported"
def user_authentication_flow(conn):
username = str(uuid.uuid4())
password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
user_attribute_name = str(uuid.uuid4())
user_attribute_value = str(uuid.uuid4())
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=str(uuid.uuid4()),
ReadAttributes=[user_attribute_name],
GenerateSecret=True,
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
client_secret = conn.describe_user_pool_client(
UserPoolId=user_pool_id, ClientId=client_id
)["UserPoolClient"]["ClientSecret"]
conn.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
# generating secret hash
key = bytes(str(client_secret).encode("latin-1"))
msg = bytes(str(username + client_id).encode("latin-1"))
new_digest = hmac.new(key, msg, hashlib.sha256).digest()
secret_hash = base64.b64encode(new_digest).decode()
result = conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": secret_hash,
},
)
result = conn.respond_to_auth_challenge(
ClientId=client_id,
ChallengeName=result["ChallengeName"],
ChallengeResponses={
"PASSWORD_CLAIM_SIGNATURE": str(uuid.uuid4()),
"PASSWORD_CLAIM_SECRET_BLOCK": result["Session"],
"TIMESTAMP": str(uuid.uuid4()),
"USERNAME": username,
},
)
refresh_token = result["AuthenticationResult"]["RefreshToken"]
# add mfa token
conn.associate_software_token(
AccessToken=result["AuthenticationResult"]["AccessToken"]
)
conn.verify_software_token(
AccessToken=result["AuthenticationResult"]["AccessToken"], UserCode="123456"
)
conn.set_user_mfa_preference(
AccessToken=result["AuthenticationResult"]["AccessToken"],
SoftwareTokenMfaSettings={"Enabled": True, "PreferredMfa": True},
)
result = conn.initiate_auth(
ClientId=client_id,
AuthFlow="REFRESH_TOKEN",
AuthParameters={"SECRET_HASH": secret_hash, "REFRESH_TOKEN": refresh_token},
)
assert result["AuthenticationResult"]["IdToken"] is not None
assert result["AuthenticationResult"]["AccessToken"] is not None
assert result["AuthenticationResult"]["TokenType"] == "Bearer"
# authenticate user once again this time with mfa token
result = conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": secret_hash,
},
)
result = conn.respond_to_auth_challenge(
ClientId=client_id,
ChallengeName=result["ChallengeName"],
ChallengeResponses={
"PASSWORD_CLAIM_SIGNATURE": str(uuid.uuid4()),
"PASSWORD_CLAIM_SECRET_BLOCK": result["Session"],
"TIMESTAMP": str(uuid.uuid4()),
"USERNAME": username,
},
)
result = conn.respond_to_auth_challenge(
ClientId=client_id,
Session=result["Session"],
ChallengeName=result["ChallengeName"],
ChallengeResponses={
"SOFTWARE_TOKEN_MFA_CODE": "123456",
"USERNAME": username,
"SECRET_HASH": secret_hash,
},
)
return {
"user_pool_id": user_pool_id,
"client_id": client_id,
"client_secret": client_secret,
"secret_hash": secret_hash,
"id_token": result["AuthenticationResult"]["IdToken"],
"access_token": result["AuthenticationResult"]["AccessToken"],
"refresh_token": refresh_token,
"username": username,
"password": password,
"additional_fields": {user_attribute_name: user_attribute_value},
}
@mock_cognitoidp
def test_user_authentication_flow():
conn = boto3.client("cognito-idp", "us-west-2")
user_authentication_flow(conn)
@mock_cognitoidp
def test_token_legitimacy():
conn = boto3.client("cognito-idp", "us-west-2")
path = "../../moto/cognitoidp/resources/jwks-public.json"
with open(os.path.join(os.path.dirname(__file__), path)) as f:
json_web_key = json.loads(f.read())["keys"][0]
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
outputs = authentication_flow(conn, auth_flow)
id_token = outputs["id_token"]
access_token = outputs["access_token"]
client_id = outputs["client_id"]
username = outputs["username"]
issuer = (
f"https://cognito-idp.us-west-2.amazonaws.com/{outputs['user_pool_id']}"
)
id_claims = json.loads(jws.verify(id_token, json_web_key, "RS256"))
assert id_claims["iss"] == issuer
assert id_claims["aud"] == client_id
assert id_claims["token_use"] == "id"
assert id_claims["cognito:username"] == username
for k, v in outputs["additional_fields"].items():
assert id_claims[k] == v
access_claims = json.loads(jws.verify(access_token, json_web_key, "RS256"))
assert access_claims["iss"] == issuer
assert access_claims["client_id"] == client_id
assert access_claims["token_use"] == "access"
assert access_claims["username"] == username
@mock_cognitoidp
def test_change_password():
conn = boto3.client("cognito-idp", "us-west-2")
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
outputs = authentication_flow(conn, auth_flow)
# Take this opportunity to test change_password, which requires an access token.
newer_password = "P2$Sword2"
conn.change_password(
AccessToken=outputs["access_token"],
PreviousPassword=outputs["password"],
ProposedPassword=newer_password,
)
# Log in again, which should succeed without a challenge because the user is no
# longer in the force-new-password state.
result = conn.admin_initiate_auth(
UserPoolId=outputs["user_pool_id"],
ClientId=outputs["client_id"],
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={
"USERNAME": outputs["username"],
"PASSWORD": newer_password,
},
)
assert result["AuthenticationResult"] is not None
@mock_cognitoidp
def test_change_password__using_custom_user_agent_header():
# https://github.com/getmoto/moto/issues/3098
# As the admin_initiate_auth-method is unauthenticated, we use the user-agent header to pass in the region
# This test verifies this works, even if we pass in our own user-agent header
from botocore.config import Config
my_config = Config(user_agent_extra="more/info", signature_version="v4")
conn = boto3.client("cognito-idp", "us-west-2", config=my_config)
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
outputs = authentication_flow(conn, auth_flow)
# Take this opportunity to test change_password, which requires an access token.
newer_password = "P2$Sword2"
conn.change_password(
AccessToken=outputs["access_token"],
PreviousPassword=outputs["password"],
ProposedPassword=newer_password,
)
# Log in again, which should succeed without a challenge because the user is no
# longer in the force-new-password state.
result = conn.admin_initiate_auth(
UserPoolId=outputs["user_pool_id"],
ClientId=outputs["client_id"],
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={
"USERNAME": outputs["username"],
"PASSWORD": newer_password,
},
)
assert result["AuthenticationResult"] is not None
@mock_cognitoidp
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"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
result = conn.forgot_password(ClientId=client_id, Username=str(uuid.uuid4()))
assert result["CodeDeliveryDetails"]["Destination"] is not None
assert result["CodeDeliveryDetails"]["DeliveryMedium"] == "EMAIL"
assert result["CodeDeliveryDetails"]["AttributeName"] == "email"
@mock_cognitoidp
def test_forgot_password_nonexistent_client_id():
conn = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
conn.forgot_password(ClientId=create_id(), Username=str(uuid.uuid4()))
err = ex.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
assert err["Message"] == "Username/client id combination not found."
@mock_cognitoidp
def test_forgot_password_admin_only_recovery():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
AccountRecoverySetting={
"RecoveryMechanisms": [{"Name": "admin_only", "Priority": 1}]
},
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
with pytest.raises(ClientError) as ex:
conn.forgot_password(ClientId=client_id, Username=str(uuid.uuid4()))
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "Contact administrator to reset password."
@mock_cognitoidp
def test_forgot_password_user_with_all_recovery_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
AccountRecoverySetting={
"RecoveryMechanisms": [{"Name": "verified_email", "Priority": 1}]
},
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
username = str(uuid.uuid4())
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[
{"Name": "email", "Value": "test@moto.com"},
{"Name": "phone_number", "Value": "555555555"},
],
)
result = conn.forgot_password(ClientId=client_id, Username=username)
assert result["CodeDeliveryDetails"]["Destination"] == "test@moto.com"
assert result["CodeDeliveryDetails"]["DeliveryMedium"] == "EMAIL"
assert result["CodeDeliveryDetails"]["AttributeName"] == "email"
conn.update_user_pool(
UserPoolId=user_pool_id,
AccountRecoverySetting={
"RecoveryMechanisms": [{"Name": "verified_phone_number", "Priority": 1}]
},
)
result = conn.forgot_password(ClientId=client_id, Username=username)
assert result["CodeDeliveryDetails"]["Destination"] == "555555555"
assert result["CodeDeliveryDetails"]["DeliveryMedium"] == "SMS"
assert result["CodeDeliveryDetails"]["AttributeName"] == "phone_number"
@mock_cognitoidp
def test_forgot_password_nonexistent_user_or_user_without_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
AccountRecoverySetting={
"RecoveryMechanisms": [{"Name": "verified_email", "Priority": 1}]
},
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
user_without_attributes = str(uuid.uuid4())
nonexistent_user = str(uuid.uuid4())
conn.admin_create_user(UserPoolId=user_pool_id, Username=user_without_attributes)
for user in user_without_attributes, nonexistent_user:
result = conn.forgot_password(ClientId=client_id, Username=user)
assert result["CodeDeliveryDetails"]["Destination"] == user + "@h***.com"
assert result["CodeDeliveryDetails"]["DeliveryMedium"] == "EMAIL"
assert result["CodeDeliveryDetails"]["AttributeName"] == "email"
conn.update_user_pool(
UserPoolId=user_pool_id,
AccountRecoverySetting={
"RecoveryMechanisms": [{"Name": "verified_phone_number", "Priority": 1}]
},
)
for user in user_without_attributes, nonexistent_user:
result = conn.forgot_password(ClientId=client_id, Username=user)
assert result["CodeDeliveryDetails"]["Destination"] == "+*******9934"
assert result["CodeDeliveryDetails"]["DeliveryMedium"] == "SMS"
assert result["CodeDeliveryDetails"]["AttributeName"] == "phone_number"
@mock_cognitoidp
def test_confirm_forgot_password_legacy():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
conn.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
# Random confirmation code - opt out of verification
conn.forgot_password(ClientId=client_id, Username=username)
res = conn.confirm_forgot_password(
ClientId=client_id,
Username=username,
ConfirmationCode=str(uuid.uuid4()),
Password=str(uuid.uuid4()),
)
assert res["ResponseMetadata"]["HTTPStatusCode"] == 200
@mock_cognitoidp
def test_confirm_forgot_password_opt_in_verification():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
conn.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
res = conn.forgot_password(ClientId=client_id, Username=username)
confirmation_code = res["ResponseMetadata"]["HTTPHeaders"][
"x-moto-forgot-password-confirmation-code"
]
assert "moto-confirmation-code" in confirmation_code
res = conn.confirm_forgot_password(
ClientId=client_id,
Username=username,
ConfirmationCode=confirmation_code,
Password=str(uuid.uuid4()),
)
assert res["ResponseMetadata"]["HTTPStatusCode"] == 200
@mock_cognitoidp
def test_confirm_forgot_password_opt_in_verification_invalid_confirmation_code():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
conn.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
with pytest.raises(ClientError) as ex:
conn.confirm_forgot_password(
ClientId=client_id,
Username=username,
ConfirmationCode="moto-confirmation-code:123invalid",
Password=str(uuid.uuid4()),
)
err = ex.value.response["Error"]
assert err["Code"] == "ExpiredCodeException"
assert err["Message"] == "Invalid code provided, please request a code again."
@mock_cognitoidp
def test_admin_user_global_sign_out():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
conn.admin_user_global_sign_out(
UserPoolId=result["user_pool_id"], Username=result["username"]
)
with pytest.raises(ClientError) as ex:
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="REFRESH_TOKEN",
AuthParameters={
"REFRESH_TOKEN": result["refresh_token"],
"SECRET_HASH": result["secret_hash"],
},
)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "Refresh Token has been revoked"
@mock_cognitoidp
def test_admin_user_global_sign_out_twice():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
conn.admin_user_global_sign_out(
UserPoolId=result["user_pool_id"], Username=result["username"]
)
conn.admin_user_global_sign_out(
UserPoolId=result["user_pool_id"], Username=result["username"]
)
with pytest.raises(ClientError) as ex:
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="REFRESH_TOKEN",
AuthParameters={
"REFRESH_TOKEN": result["refresh_token"],
"SECRET_HASH": result["secret_hash"],
},
)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "Refresh Token has been revoked"
@mock_cognitoidp
def test_admin_user_global_sign_out_unknown_userpool():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
with pytest.raises(ClientError) as ex:
conn.admin_user_global_sign_out(UserPoolId="n/a", Username=result["username"])
err = ex.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
@mock_cognitoidp
def test_admin_user_global_sign_out_unknown_user():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
with pytest.raises(ClientError) as ex:
conn.admin_user_global_sign_out(
UserPoolId=result["user_pool_id"], Username="n/a"
)
err = ex.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
assert err["Message"] == "User does not exist."
@mock_cognitoidp
def test_global_sign_out():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
conn.global_sign_out(AccessToken=result["access_token"])
with pytest.raises(ClientError) as ex:
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="REFRESH_TOKEN",
AuthParameters={
"REFRESH_TOKEN": result["refresh_token"],
"SECRET_HASH": result["secret_hash"],
},
)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "Refresh Token has been revoked"
with pytest.raises(ClientError) as ex:
conn.get_user(AccessToken=result["access_token"])
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_global_sign_out_unknown_accesstoken():
conn = boto3.client("cognito-idp", "us-east-2")
with pytest.raises(ClientError) as ex:
conn.global_sign_out(AccessToken="n/a")
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_admin_update_user_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[
{"Name": "family_name", "Value": "Doe"},
{"Name": "given_name", "Value": "John"},
],
)
conn.admin_update_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[
{"Name": "family_name", "Value": "Doe"},
{"Name": "given_name", "Value": "Jane"},
],
)
user = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
attributes = user["UserAttributes"]
for attr in attributes:
val = attr["Value"]
if attr["Name"] == "family_name":
assert val == "Doe"
elif attr["Name"] == "given_name":
assert val == "Jane"
@mock_cognitoidp
def test_admin_delete_user_attributes():
conn = boto3.client("cognito-idp", "us-east-1")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Schema=[
{
"Name": "foo",
"AttributeDataType": "String",
"Mutable": True,
"Required": False,
}
],
)["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[
{"Name": "family_name", "Value": "Doe"},
{"Name": "given_name", "Value": "John"},
{"Name": "nickname", "Value": "Joe"},
{"Name": "custom:foo", "Value": "bar"},
],
)
conn.admin_delete_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributeNames=["nickname", "custom:foo"],
)
user = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert len(user["UserAttributes"]) == 3 # family_name, given_name and sub
assert {"Name": "family_name", "Value": "Doe"} in user["UserAttributes"]
assert {"Name": "given_name", "Value": "John"} in user["UserAttributes"]
assert {"Name": "nickname", "Value": "Joe"} not in user["UserAttributes"]
assert {"Name": "custom:foo", "Value": "bar"} not in user["UserAttributes"]
@mock_cognitoidp
def test_admin_delete_user_attributes_non_existing_attribute():
conn = boto3.client("cognito-idp", "us-east-1")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[
{"Name": "family_name", "Value": "Doe"},
{"Name": "given_name", "Value": "John"},
{"Name": "nickname", "Value": "Joe"},
],
)
with pytest.raises(ClientError) as exc:
conn.admin_delete_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributeNames=["nickname", "custom:foo"],
)
err = exc.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert (
err["Message"]
== "Invalid user attributes: user.custom:foo: Attribute does not exist in the schema.\n"
)
with pytest.raises(ClientError) as exc:
conn.admin_delete_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributeNames=["nickname", "custom:foo", "custom:bar"],
)
err = exc.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert (
err["Message"]
== "Invalid user attributes: user.custom:foo: Attribute does not exist in the schema.\nuser.custom:bar: Attribute does not exist in the schema.\n"
)
@mock_cognitoidp
def test_admin_delete_user_attributes_non_existing_user():
conn = boto3.client("cognito-idp", "us-east-1")
username = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
with pytest.raises(ClientError) as exc:
conn.admin_delete_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributeNames=["nickname", "custom:foo"],
)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
assert err["Message"] == "User does not exist."
@mock_cognitoidp
def test_admin_delete_user_attributes_non_existing_pool():
conn = boto3.client("cognito-idp", "us-east-1")
user_pool_id = "us-east-1_aaaaaaaa"
with pytest.raises(ClientError) as exc:
conn.admin_delete_user_attributes(
UserPoolId=user_pool_id,
Username=str(uuid.uuid4()),
UserAttributeNames=["nickname"],
)
err = exc.value.response["Error"]
assert err["Code"] == "ResourceNotFoundException"
assert err["Message"] == f"User pool {user_pool_id} does not exist."
@mock_cognitoidp
def test_update_user_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
result = authentication_flow(conn, auth_flow="ADMIN_USER_PASSWORD_AUTH")
access_token = result["access_token"]
username = result["username"]
user_pool_id = result["user_pool_id"]
conn.update_user_attributes(
AccessToken=access_token,
UserAttributes=[
{"Name": "family_name", "Value": "Doe"},
{"Name": "given_name", "Value": "Jane"},
],
)
user = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
attributes = user["UserAttributes"]
assert {"Name": "family_name", "Value": "Doe"} in attributes
assert {"Name": "given_name", "Value": "Jane"} in attributes
@mock_cognitoidp
def test_update_user_attributes_unknown_accesstoken():
conn = boto3.client("cognito-idp", "us-east-2")
with pytest.raises(ClientError) as ex:
conn.update_user_attributes(
AccessToken="n/a", UserAttributes=[{"Name": "a", "Value": "b"}]
)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_create_resource_server():
client = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
res = client.create_user_pool(PoolName=name)
user_pool_id = res["UserPool"]["Id"]
identifier = "http://localhost.localdomain"
name = "local server"
scopes = [
{"ScopeName": "app:write", "ScopeDescription": "write scope"},
{"ScopeName": "app:read", "ScopeDescription": "read scope"},
]
res = client.create_resource_server(
UserPoolId=user_pool_id, Identifier=identifier, Name=name, Scopes=scopes
)
assert res["ResourceServer"]["UserPoolId"] == user_pool_id
assert res["ResourceServer"]["Identifier"] == identifier
assert res["ResourceServer"]["Name"] == name
assert res["ResourceServer"]["Scopes"] == scopes
with pytest.raises(ClientError) as ex:
client.create_resource_server(
UserPoolId=user_pool_id, Identifier=identifier, Name=name, Scopes=scopes
)
assert ex.value.operation_name == "CreateResourceServer"
assert ex.value.response["Error"]["Code"] == "InvalidParameterException"
assert (
ex.value.response["Error"]["Message"]
== f"{identifier} already exists in user pool {user_pool_id}."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_create_resource_server_with_no_scopes():
client = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
res = client.create_user_pool(PoolName=name)
user_pool_id = res["UserPool"]["Id"]
identifier = "http://localhost.localdomain"
name = "local server"
res = client.create_resource_server(
UserPoolId=user_pool_id, Identifier=identifier, Name=name
)
assert res["ResourceServer"]["UserPoolId"] == user_pool_id
assert res["ResourceServer"]["Identifier"] == identifier
assert res["ResourceServer"]["Name"] == name
assert "Scopes" not in res["ResourceServer"]
@mock_cognitoidp
def test_describe_resource_server():
# Create a user pool to attach a resource server to
client = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
user_pool = client.create_user_pool(PoolName=name)
user_pool_id = user_pool["UserPool"]["Id"]
server_id = "my_server"
server_name = "new_remote_server"
scopes = [
{"ScopeName": "app:write", "ScopeDescription": "write scope"},
{"ScopeName": "app:read", "ScopeDescription": "read scope"},
]
# Create a new resource server
new_resource_server = client.create_resource_server(
UserPoolId=user_pool_id, Identifier=server_id, Name=server_name, Scopes=scopes
)
assert new_resource_server["ResourceServer"]["UserPoolId"] == user_pool_id
assert new_resource_server["ResourceServer"]["Identifier"] == server_id
assert new_resource_server["ResourceServer"]["Name"] == server_name
assert new_resource_server["ResourceServer"]["Scopes"] == scopes
# Describe the newly created resource server
response = client.describe_resource_server(
UserPoolId=user_pool_id, Identifier=server_id
)
# Assert all the values we expect are seen in the description.
assert response["ResourceServer"]["UserPoolId"] == user_pool_id
assert response["ResourceServer"]["Identifier"] == server_id
assert response["ResourceServer"]["Name"] == server_name
assert response["ResourceServer"]["Scopes"] == scopes
# Make sure attempting to describe a non-existent server fails in
# the expected manner
fake_server_id = "non_existent_server"
negative_response = None
with pytest.raises(ClientError) as ex:
negative_response = client.describe_resource_server(
UserPoolId=user_pool_id, Identifier=fake_server_id
)
# Assert that error message content is what's expected for a failure.
assert negative_response is None
assert ex.value.operation_name == "DescribeResourceServer"
assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException"
assert (
ex.value.response["Error"]["Message"]
== f"Resource server {fake_server_id} does not exist."
)
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
@mock_cognitoidp
def test_list_resource_servers_empty_set():
# Create a user pool to attach a resource server to
client = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
user_pool = client.create_user_pool(PoolName=name)
user_pool_id = user_pool["UserPool"]["Id"]
# Empty list, because we aren't creating any.
all_resource_svrs = []
max_return = 50
servers = client.list_resource_servers(
UserPoolId=user_pool_id, MaxResults=max_return
)
expected_keys = ["ResourceServers", "ResponseMetadata"]
assert all(key in servers for key in expected_keys)
assert servers["ResponseMetadata"].get("HTTPStatusCode")
assert servers["ResponseMetadata"]["HTTPStatusCode"] == 200
assert servers.get("NextToken", False) is False
assert len(servers["ResourceServers"]) == len(all_resource_svrs)
assert len(servers["ResourceServers"]) == 0
@mock_cognitoidp
def test_list_resource_servers_single_page():
# Create a user pool to attach a resource server to
client = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
user_pool = client.create_user_pool(PoolName=name)
user_pool_id = user_pool["UserPool"]["Id"]
create_num = 48
all_resource_svrs = []
for id_num in range(0, create_num, 1):
server_id = f"my_server{id_num}"
server_name = "new_remote_server{id_num}"
scopes = [
{
"ScopeName": f"app:write{id_num}",
"ScopeDescription": f"write scope{id_num}",
},
{
"ScopeName": f"app:read{id_num}",
"ScopeDescription": f"read scope{id_num}",
},
]
# Create a new resource server
new_resource_server = client.create_resource_server(
UserPoolId=user_pool_id,
Identifier=server_id,
Name=server_name,
Scopes=scopes,
)
all_resource_svrs.append(new_resource_server)
max_return = 50
servers = client.list_resource_servers(
UserPoolId=user_pool_id, MaxResults=max_return
)
expected_keys = ["ResourceServers", "ResponseMetadata"]
assert all(key in servers for key in expected_keys)
assert servers["ResponseMetadata"].get("HTTPStatusCode")
assert servers["ResponseMetadata"]["HTTPStatusCode"] == 200
assert servers.get("NextToken", False) is False
assert len(servers["ResourceServers"]) == create_num
returned_servers = servers["ResourceServers"]
for idx in range(0, create_num - 1, 1):
for key in returned_servers[idx].keys():
assert (
returned_servers[idx][key]
== all_resource_svrs[idx]["ResourceServer"][key]
)
@mock_cognitoidp
def test_list_resource_servers_multi_page():
# Create a user pool to attach a resource server to
client = boto3.client("cognito-idp", "us-west-2")
name = str(uuid.uuid4())
user_pool = client.create_user_pool(PoolName=name)
user_pool_id = user_pool["UserPool"]["Id"]
create_num = 65
all_resource_svrs = []
for id_num in range(0, create_num, 1):
server_id = f"my_server{id_num}"
server_name = "new_remote_server{id_num}"
scopes = [
{
"ScopeName": f"app:write{id_num}",
"ScopeDescription": f"write scope{id_num}",
},
{
"ScopeName": f"app:read{id_num}",
"ScopeDescription": f"read scope{id_num}",
},
]
# Create a new resource server
new_resource_server = client.create_resource_server(
UserPoolId=user_pool_id,
Identifier=server_id,
Name=server_name,
Scopes=scopes,
)
all_resource_svrs.append(new_resource_server)
max_return = 50
servers = client.list_resource_servers(
UserPoolId=user_pool_id, MaxResults=max_return
)
expected_keys = ["ResourceServers", "NextToken", "ResponseMetadata"]
assert all(key in servers for key in expected_keys)
assert servers["ResponseMetadata"].get("HTTPStatusCode")
assert servers["ResponseMetadata"]["HTTPStatusCode"] == 200
assert servers.get("NextToken", False)
assert len(servers["ResourceServers"]) == max_return
returned_servers = servers["ResourceServers"]
for idx in range(0, max_return - 1, 1):
for key in returned_servers[idx].keys():
assert (
returned_servers[idx][key]
== all_resource_svrs[idx]["ResourceServer"][key]
)
next_page = client.list_resource_servers(
UserPoolId=user_pool_id, MaxResults=max_return, NextToken=servers["NextToken"]
)
expected_keys = ["ResourceServers", "ResponseMetadata"]
expected_returns = create_num - max_return
assert all(key in next_page for key in expected_keys)
assert next_page["ResponseMetadata"].get("HTTPStatusCode")
assert next_page["ResponseMetadata"]["HTTPStatusCode"] == 200
assert next_page.get("NextToken", False) is False
assert len(next_page["ResourceServers"]) == expected_returns
returned_servers = next_page["ResourceServers"]
# Check the second page of results
# Each entry in the second page should be the offset of 'max_return + idx' in all_resource_svrs
for idx in range(0, expected_returns, 1):
for key in returned_servers[idx].keys():
all_idx = idx + max_return
assert (
returned_servers[idx][key]
== all_resource_svrs[all_idx]["ResourceServer"][key]
)
@mock_cognitoidp
def test_sign_up():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
username = str(uuid.uuid4())
password = "P2$Sword"
result = conn.sign_up(ClientId=client_id, Username=username, Password=password)
assert result["UserConfirmed"] is False
assert result["UserSub"] is not None
@mock_cognitoidp
@pytest.mark.parametrize("password", ["p2$$word", "P2$s"])
def test_sign_up_with_invalid_password(password):
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
username = str(uuid.uuid4())
with pytest.raises(ClientError) as exc:
conn.sign_up(ClientId=client_id, Username=username, Password=password)
err = exc.value.response["Error"]
assert err["Code"] == "InvalidPasswordException"
@mock_cognitoidp
def test_sign_up_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email", "phone_number"]
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
username = str(uuid.uuid4())
password = "P2$Sword"
with pytest.raises(ClientError) as err:
# Attempt to add user again
conn.sign_up(ClientId=client_id, Username=username, Password=password)
assert err.value.response["Error"]["Code"] == "InvalidParameterException"
username = "test@example.com"
result = conn.sign_up(ClientId=client_id, Username=username, Password=password)
assert result["UserConfirmed"] is False
assert result["UserSub"] is not None
username = "+123456789"
result = conn.sign_up(ClientId=client_id, Username=username, Password=password)
assert result["UserConfirmed"] is False
assert result["UserSub"] is not None
@mock_cognitoidp
def test_sign_up_existing_user():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4())
)["UserPoolClient"]["ClientId"]
username = str(uuid.uuid4())
password = "P2$Sword"
# Add initial user
conn.sign_up(ClientId=client_id, Username=username, Password=password)
with pytest.raises(ClientError) as err:
# Attempt to add user again
conn.sign_up(ClientId=client_id, Username=username, Password=password)
assert err.value.response["Error"]["Code"] == "UsernameExistsException"
@mock_cognitoidp
def test_confirm_sign_up():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
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_cognitoidp
def test_confirm_sign_up_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
password = "P2$Sword"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
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_cognitoidp
def test_initiate_auth_USER_SRP_AUTH():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
client_secret = conn.describe_user_pool_client(
UserPoolId=user_pool_id, ClientId=client_id
)["UserPoolClient"]["ClientSecret"]
conn.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
key = bytes(str(client_secret).encode("latin-1"))
msg = bytes(str(username + client_id).encode("latin-1"))
new_digest = hmac.new(key, msg, hashlib.sha256).digest()
secret_hash = base64.b64encode(new_digest).decode()
result = conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": secret_hash,
},
)
assert result["ChallengeName"] == "PASSWORD_VERIFIER"
assert result["ChallengeParameters"]["USERNAME"] == username
@mock_cognitoidp
def test_initiate_auth_USER_SRP_AUTH_with_username_attributes():
conn = boto3.client("cognito-idp", "us-west-2")
username = "test@example.com"
password = "P2$Sword"
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
client_secret = conn.describe_user_pool_client(
UserPoolId=user_pool_id, ClientId=client_id
)["UserPoolClient"]["ClientSecret"]
conn.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
key = bytes(str(client_secret).encode("latin-1"))
msg = bytes(str(username + client_id).encode("latin-1"))
new_digest = hmac.new(key, msg, hashlib.sha256).digest()
secret_hash = base64.b64encode(new_digest).decode()
result = conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": secret_hash,
},
)
assert result["ChallengeName"] == "PASSWORD_VERIFIER"
@mock_cognitoidp
def test_initiate_auth_REFRESH_TOKEN():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
result = conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="REFRESH_TOKEN",
AuthParameters={
"REFRESH_TOKEN": result["refresh_token"],
"SECRET_HASH": result["secret_hash"],
},
)
assert result["AuthenticationResult"]["AccessToken"] is not None
@mock_cognitoidp
def test_initiate_auth_USER_PASSWORD_AUTH():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
result = conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": result["username"], "PASSWORD": result["password"]},
)
assert result["AuthenticationResult"]["AccessToken"] is not None
assert result["AuthenticationResult"]["IdToken"] is not None
assert result["AuthenticationResult"]["RefreshToken"] is not None
assert result["AuthenticationResult"]["TokenType"] == "Bearer"
@mock_cognitoidp
def test_initiate_auth_invalid_auth_flow():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
with pytest.raises(ClientError) as ex:
user_authentication_flow(conn)
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="NO_SUCH_FLOW",
AuthParameters={
"USERNAME": result["username"],
"PASSWORD": result["password"],
},
)
err = ex.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert (
err["Message"]
== "1 validation error detected: Value 'NO_SUCH_FLOW' at 'authFlow' failed to satisfy constraint: Member must satisfy enum value set: ['ADMIN_NO_SRP_AUTH', 'ADMIN_USER_PASSWORD_AUTH', 'USER_SRP_AUTH', 'REFRESH_TOKEN_AUTH', 'REFRESH_TOKEN', 'CUSTOM_AUTH', 'USER_PASSWORD_AUTH']"
)
@mock_cognitoidp
def test_initiate_auth_invalid_admin_auth_flow():
"""Pass an admin auth_flow to the regular initiate_auth"""
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
with pytest.raises(ClientError) as ex:
user_authentication_flow(conn)
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="ADMIN_USER_PASSWORD_AUTH",
AuthParameters={
"USERNAME": result["username"],
"PASSWORD": result["password"],
},
)
err = ex.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert err["Message"] == "Initiate Auth method not supported"
@mock_cognitoidp
def test_initiate_auth_USER_PASSWORD_AUTH_with_FORCE_CHANGE_PASSWORD_status():
# Test flow:
# 1. Create user with FORCE_CHANGE_PASSWORD status
# 2. Login with temporary password
# 3. Check that the right challenge is received
# 4. Respond to challenge with new password
# 5. Check that the access tokens are received
client = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
# Create pool and client
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = client.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
# Create user in status FORCE_CHANGE_PASSWORD
temporary_password = "P2$Sword"
client.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=temporary_password
)
result = client.initiate_auth(
ClientId=client_id,
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
assert result["ChallengeName"] == "NEW_PASSWORD_REQUIRED"
assert result["ChallengeParameters"]["USERNAME"] == username
assert result["Session"] != ""
assert result.get("AuthenticationResult") is None
new_password = "P2$Sword2"
result = client.respond_to_auth_challenge(
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
Session=result["Session"],
ChallengeResponses={
"NEW_PASSWORD": new_password,
"USERNAME": result["ChallengeParameters"]["USERNAME"],
},
)
assert result["AuthenticationResult"]["IdToken"] != ""
assert result["AuthenticationResult"]["AccessToken"] != ""
@mock_cognitoidp
def test_initiate_auth_USER_PASSWORD_AUTH_user_not_found():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
with pytest.raises(ClientError) as ex:
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": "INVALIDUSER", "PASSWORD": result["password"]},
)
err = ex.value.response["Error"]
assert err["Code"] == "UserNotFoundException"
@mock_cognitoidp
def test_initiate_auth_USER_PASSWORD_AUTH_user_incorrect_password():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
with pytest.raises(ClientError) as ex:
conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={
"USERNAME": result["username"],
"PASSWORD": "NotAuthorizedException",
},
)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_initiate_auth_USER_PASSWORD_AUTH_unconfirmed_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
with pytest.raises(ClientError) as ex:
conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": password},
)
err = ex.value.response["Error"]
assert err["Code"] == "UserNotConfirmedException"
@mock_cognitoidp
def test_initiate_auth_for_unconfirmed_user():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
client_secret = conn.describe_user_pool_client(
UserPoolId=user_pool_id, ClientId=client_id
)["UserPoolClient"]["ClientSecret"]
key = bytes(str(client_secret).encode("latin-1"))
msg = bytes(str(username + client_id).encode("latin-1"))
new_digest = hmac.new(key, msg, hashlib.sha256).digest()
secret_hash = base64.b64encode(new_digest).decode()
with pytest.raises(ClientError) as exc:
conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": secret_hash,
},
)
err = exc.value.response["Error"]
assert err["Code"] == "UserNotConfirmedException"
@mock_cognitoidp
def test_initiate_auth_with_invalid_secret_hash():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
conn.sign_up(ClientId=client_id, Username=username, Password=password)
conn.describe_user_pool_client(UserPoolId=user_pool_id, ClientId=client_id)
conn.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
invalid_secret_hash = str(uuid.uuid4())
with pytest.raises(ClientError) as exc:
conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": invalid_secret_hash,
},
)
err = exc.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_setting_mfa():
conn = boto3.client("cognito-idp", "us-west-2")
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
result = authentication_flow(conn, auth_flow)
# Set MFA method
conn.associate_software_token(AccessToken=result["access_token"])
conn.verify_software_token(
AccessToken=result["access_token"], UserCode="123456"
)
conn.set_user_mfa_preference(
AccessToken=result["access_token"],
SoftwareTokenMfaSettings={"Enabled": True, "PreferredMfa": True},
)
user = conn.admin_get_user(
UserPoolId=result["user_pool_id"], Username=result["username"]
)
assert len(user["UserMFASettingList"]) == 1
assert user["PreferredMfaSetting"] == "SOFTWARE_TOKEN_MFA"
# Unset MFA method
conn.set_user_mfa_preference(
AccessToken=result["access_token"],
SoftwareTokenMfaSettings={"Enabled": False, "PreferredMfa": False},
)
user = conn.admin_get_user(
UserPoolId=result["user_pool_id"], Username=result["username"]
)
assert len(user["UserMFASettingList"]) == 0
assert user["PreferredMfaSetting"] == ""
@mock_cognitoidp
def test_setting_mfa_when_token_not_verified():
conn = boto3.client("cognito-idp", "us-west-2")
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
result = authentication_flow(conn, auth_flow)
conn.associate_software_token(AccessToken=result["access_token"])
with pytest.raises(ClientError) as exc:
conn.set_user_mfa_preference(
AccessToken=result["access_token"],
SoftwareTokenMfaSettings={"Enabled": True, "PreferredMfa": True},
)
err = exc.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
@mock_cognitoidp
def test_admin_setting_single_mfa():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
username = "test@example.com"
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
# Set MFA SMS method
conn.admin_set_user_mfa_preference(
Username=username,
UserPoolId=user_pool_id,
SMSMfaSettings={"Enabled": True, "PreferredMfa": True},
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert len(result["UserMFASettingList"]) == 1
assert result["PreferredMfaSetting"] == "SMS_MFA"
# Unset MFA SMS method
conn.admin_set_user_mfa_preference(
Username=username,
UserPoolId=user_pool_id,
SMSMfaSettings={"Enabled": False, "PreferredMfa": False},
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert len(result["UserMFASettingList"]) == 0
assert result["PreferredMfaSetting"] == ""
@mock_cognitoidp
def test_admin_setting_mfa_totp_and_sms():
conn = boto3.client("cognito-idp", "us-west-2")
result = authentication_flow(conn, "ADMIN_NO_SRP_AUTH")
access_token = result["access_token"]
user_pool_id = result["user_pool_id"]
username = result["username"]
conn.associate_software_token(AccessToken=access_token)
conn.verify_software_token(AccessToken=access_token, UserCode="123456")
# Set MFA TOTP and SMS methods
conn.admin_set_user_mfa_preference(
Username=username,
UserPoolId=user_pool_id,
SoftwareTokenMfaSettings={"Enabled": True, "PreferredMfa": True},
SMSMfaSettings={"Enabled": True, "PreferredMfa": False},
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert len(result["UserMFASettingList"]) == 2
assert result["PreferredMfaSetting"] == "SOFTWARE_TOKEN_MFA"
# Unset MFA TOTP and SMS methods
conn.admin_set_user_mfa_preference(
Username=username,
UserPoolId=user_pool_id,
SoftwareTokenMfaSettings={"Enabled": False, "PreferredMfa": False},
SMSMfaSettings={"Enabled": False, "PreferredMfa": False},
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert len(result["UserMFASettingList"]) == 0
assert result["PreferredMfaSetting"] == ""
@mock_cognitoidp
def test_admin_initiate_auth_when_token_totp_enabled():
conn = boto3.client("cognito-idp", "us-west-2")
result = authentication_flow(conn, "ADMIN_NO_SRP_AUTH")
access_token = result["access_token"]
user_pool_id = result["user_pool_id"]
username = result["username"]
client_id = result["client_id"]
password = result["password"]
conn.associate_software_token(AccessToken=access_token)
conn.verify_software_token(AccessToken=access_token, UserCode="123456")
# Set MFA TOTP and SMS methods
conn.admin_set_user_mfa_preference(
Username=username,
UserPoolId=user_pool_id,
SoftwareTokenMfaSettings={"Enabled": True, "PreferredMfa": True},
SMSMfaSettings={"Enabled": True, "PreferredMfa": False},
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert len(result["UserMFASettingList"]) == 2
assert result["PreferredMfaSetting"] == "SOFTWARE_TOKEN_MFA"
# Initiate auth with TOTP
result = conn.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"PASSWORD": password,
},
)
assert result["ChallengeName"] == "SOFTWARE_TOKEN_MFA"
assert result["Session"] != ""
# Respond to challenge with TOTP
result = conn.admin_respond_to_auth_challenge(
UserPoolId=user_pool_id,
ClientId=client_id,
ChallengeName="SOFTWARE_TOKEN_MFA",
Session=result["Session"],
ChallengeResponses={
"SOFTWARE_TOKEN_MFA_CODE": "123456",
"USERNAME": username,
},
)
assert result["AuthenticationResult"]["IdToken"] != ""
assert result["AuthenticationResult"]["AccessToken"] != ""
assert result["AuthenticationResult"]["RefreshToken"] != ""
assert result["AuthenticationResult"]["TokenType"] == "Bearer"
@mock_cognitoidp
def test_admin_setting_mfa_when_token_not_verified():
conn = boto3.client("cognito-idp", "us-west-2")
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()), UsernameAttributes=["email"]
)["UserPool"]["Id"]
username = "test@example.com"
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
with pytest.raises(conn.exceptions.InvalidParameterException):
conn.admin_set_user_mfa_preference(
Username=username,
UserPoolId=user_pool_id,
SoftwareTokenMfaSettings={"Enabled": True, "PreferredMfa": True},
)
@mock_cognitoidp
def test_respond_to_auth_challenge_with_invalid_secret_hash():
conn = boto3.client("cognito-idp", "us-west-2")
result = user_authentication_flow(conn)
valid_secret_hash = result["secret_hash"]
invalid_secret_hash = str(uuid.uuid4())
challenge = conn.initiate_auth(
ClientId=result["client_id"],
AuthFlow="USER_SRP_AUTH",
AuthParameters={
"USERNAME": result["username"],
"SRP_A": uuid.uuid4().hex,
"SECRET_HASH": valid_secret_hash,
},
)
challenge = conn.respond_to_auth_challenge(
ClientId=result["client_id"],
ChallengeName=challenge["ChallengeName"],
ChallengeResponses={
"PASSWORD_CLAIM_SIGNATURE": str(uuid.uuid4()),
"PASSWORD_CLAIM_SECRET_BLOCK": challenge["Session"],
"TIMESTAMP": str(uuid.uuid4()),
"USERNAME": result["username"],
},
)
with pytest.raises(ClientError) as exc:
conn.respond_to_auth_challenge(
ClientId=result["client_id"],
Session=challenge["Session"],
ChallengeName=challenge["ChallengeName"],
ChallengeResponses={
"SOFTWARE_TOKEN_MFA_CODE": "123456",
"USERNAME": result["username"],
"SECRET_HASH": invalid_secret_hash,
},
)
err = exc.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_admin_set_user_password():
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
password = "P2$$word"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
conn.admin_set_user_password(
UserPoolId=user_pool_id, Username=username, Password=password, Permanent=True
)
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert result["Username"] == username
assert len(result["UserAttributes"]) == 2
def _verify_attribute(name, v):
attr = [a for a in result["UserAttributes"] if a["Name"] == name]
assert len(attr) == 1
assert attr[0]["Value"] == v
_verify_attribute("thing", value)
@mock_cognitoidp
@pytest.mark.parametrize("password", ["pa$$word", "Password", "p2ssword", "P2$S"])
def test_admin_set_invalid_user_password(password):
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
with pytest.raises(ClientError) as exc:
conn.admin_set_user_password(
UserPoolId=user_pool_id,
Username=username,
Password=password,
Permanent=True,
)
err = exc.value.response["Error"]
assert err["Code"] == "InvalidPasswordException"
@mock_cognitoidp
@pytest.mark.parametrize("password", ["password", "P2$$word"])
def test_admin_set_invalid_user_password__custom_policy_provided(password):
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
value = str(uuid.uuid4())
user_pool_id = conn.create_user_pool(
PoolName=str(uuid.uuid4()),
Policies={
"PasswordPolicy": {
"MinimumLength": 12,
"RequireUppercase": False,
"RequireLowercase": False,
"RequireNumbers": False,
"RequireSymbols": False,
}
},
)["UserPool"]["Id"]
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "thing", "Value": value}],
)
with pytest.raises(ClientError) as exc:
conn.admin_set_user_password(
UserPoolId=user_pool_id,
Username=username,
Password=password,
Permanent=True,
)
err = exc.value.response["Error"]
assert err["Code"] == "InvalidPasswordException"
# We can set a plain password, as long as it's 12 characters long
conn.admin_set_user_password(
UserPoolId=user_pool_id,
Username=username,
Password="longpassword",
Permanent=True,
)
@mock_cognitoidp
def test_change_password_with_invalid_token_raises_error():
client = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
client.change_password(
AccessToken=str(uuid.uuid4()),
PreviousPassword="previous_password",
ProposedPassword="newer_password",
)
assert ex.value.response["Error"]["Code"] == "NotAuthorizedException"
@mock_cognitoidp
def test_confirm_forgot_password_with_non_existent_client_id_raises_error():
client = boto3.client("cognito-idp", "us-west-2")
with pytest.raises(ClientError) as ex:
client.confirm_forgot_password(
ClientId="non-existent-client-id",
Username="not-existent-username",
ConfirmationCode=str(uuid.uuid4()),
Password=str(uuid.uuid4()),
)
assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException"
@mock_cognitoidp
def test_admin_reset_password_and_change_password():
client = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
temporary_pass = str(uuid.uuid4())
# Create pool and client
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = client.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
# Create CONFIRMED user with verified email
client.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=temporary_pass
)
client.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
client.admin_update_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "email_verified", "Value": "true"}],
)
# User should be in RESET_REQUIRED state after reset
client.admin_reset_user_password(UserPoolId=user_pool_id, Username=username)
result = client.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert result["UserStatus"] == "RESET_REQUIRED"
# Return to CONFIRMED status after NEW_PASSWORD_REQUIRED auth challenge
auth_result = client.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_pass},
)
password = "Admin123!"
auth_result = client.respond_to_auth_challenge(
Session=auth_result["Session"],
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": password},
)
result = client.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert result["UserStatus"] == "CONFIRMED"
# Return to CONFIRMED after user-initated password change
client.admin_reset_user_password(UserPoolId=user_pool_id, Username=username)
client.change_password(
AccessToken=auth_result["AuthenticationResult"]["AccessToken"],
PreviousPassword=password,
ProposedPassword="Admin1234!",
)
result = client.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert result["UserStatus"] == "CONFIRMED"
@mock_cognitoidp
def test_admin_initiate_auth__use_access_token():
client = boto3.client("cognito-idp", "us-west-2")
un = str(uuid.uuid4())
pw = str(uuid.uuid4())
# Create pool and client
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = client.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
client.admin_create_user(UserPoolId=user_pool_id, Username=un, TemporaryPassword=pw)
client.confirm_sign_up(ClientId=client_id, Username=un, ConfirmationCode="123456")
# Initiate once, to get a refresh token
auth_result = client.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={"USERNAME": un, "PASSWORD": pw},
)
refresh_token = auth_result["AuthenticationResult"]["RefreshToken"]
# Initiate Auth using a Refresh Token
auth_result = client.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="REFRESH_TOKEN",
AuthParameters={"REFRESH_TOKEN": refresh_token},
)
access_token = auth_result["AuthenticationResult"]["AccessToken"]
# Verify the AccessToken of this authentication works
client.global_sign_out(AccessToken=access_token)
@mock_cognitoidp
def test_admin_reset_password_disabled_user():
client = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
# Create pool
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Create disabled user
client.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
client.admin_disable_user(UserPoolId=user_pool_id, Username=username)
with pytest.raises(ClientError) as ex:
client.admin_reset_user_password(UserPoolId=user_pool_id, Username=username)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "User is disabled"
@mock_cognitoidp
def test_admin_reset_password_unconfirmed_user():
client = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
# Create pool
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
# Create user in status FORCE_CHANGE_PASSWORD
client.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
with pytest.raises(ClientError) as ex:
client.admin_reset_user_password(UserPoolId=user_pool_id, Username=username)
err = ex.value.response["Error"]
assert err["Code"] == "NotAuthorizedException"
assert err["Message"] == "User password cannot be reset in the current state."
@mock_cognitoidp
def test_admin_reset_password_no_verified_notification_channel():
client = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
# Create pool and client
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = client.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
# Create CONFIRMED user without verified email or phone
client.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
client.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
with pytest.raises(ClientError) as ex:
client.admin_reset_user_password(UserPoolId=user_pool_id, Username=username)
err = ex.value.response["Error"]
assert err["Code"] == "InvalidParameterException"
assert (
err["Message"]
== "Cannot reset password for the user as there is no registered/verified email or phone_number"
)
@mock_cognitoidp
def test_admin_reset_password_multiple_invocations():
client = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
# Create pool and client
user_pool_id = client.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
client_id = client.create_user_pool_client(
UserPoolId=user_pool_id, ClientName=str(uuid.uuid4()), GenerateSecret=True
)["UserPoolClient"]["ClientId"]
# Create CONFIRMED user with verified email
client.admin_create_user(
UserPoolId=user_pool_id, Username=username, TemporaryPassword=str(uuid.uuid4())
)
client.confirm_sign_up(
ClientId=client_id, Username=username, ConfirmationCode="123456"
)
client.admin_update_user_attributes(
UserPoolId=user_pool_id,
Username=username,
UserAttributes=[{"Name": "email_verified", "Value": "true"}],
)
for _ in range(3):
client.admin_reset_user_password(UserPoolId=user_pool_id, Username=username)
user = client.admin_get_user(UserPoolId=user_pool_id, Username=username)
assert user["UserStatus"] == "RESET_REQUIRED"
@mock_cognitoidp
def test_login_denied_if_account_disabled():
"""Make sure a disabled account is denied login"""
conn = boto3.client("cognito-idp", "us-west-2")
username = str(uuid.uuid4())
temporary_password = "P2$Sword"
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
user_attribute_name = str(uuid.uuid4())
user_attribute_value = str(uuid.uuid4())
client_id = conn.create_user_pool_client(
UserPoolId=user_pool_id,
ClientName=str(uuid.uuid4()),
ReadAttributes=[user_attribute_name],
)["UserPoolClient"]["ClientId"]
# Create a user and disable the account
conn.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
TemporaryPassword=temporary_password,
UserAttributes=[{"Name": user_attribute_name, "Value": user_attribute_value}],
)
conn.admin_disable_user(
UserPoolId=user_pool_id,
Username=username,
)
# User should not be able to login into a disabled account
with pytest.raises(conn.exceptions.NotAuthorizedException) as ex:
conn.initiate_auth(
ClientId=client_id,
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
assert ex.value.response["Error"]["Code"] == "NotAuthorizedException"
assert ex.value.response["Error"]["Message"] == "User is disabled."
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
# Using admin login should yield the same result
with pytest.raises(conn.exceptions.NotAuthorizedException) as ex:
conn.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
assert ex.value.response["Error"]["Code"] == "NotAuthorizedException"
assert ex.value.response["Error"]["Message"] == "User is disabled."
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
# Test will retrieve public key from cognito.amazonaws.com/.well-known/jwks.json,
# which isnt mocked in ServerMode
if not settings.TEST_SERVER_MODE:
@mock_cognitoidp
def test_idtoken_contains_kid_header():
# https://github.com/getmoto/moto/issues/3078
# Setup
cognito = boto3.client("cognito-idp", "us-west-2")
user_pool_id = cognito.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"][
"Id"
]
client = cognito.create_user_pool_client(
UserPoolId=user_pool_id,
ExplicitAuthFlows=[
"ALLOW_ADMIN_USER_PASSWORD_AUTH",
"ALLOW_REFRESH_TOKEN_AUTH",
"ALLOW_ADMIN_NO_SRP_AUTH",
],
AllowedOAuthFlows=["code", "implicit"],
ClientName=str(uuid.uuid4()),
CallbackURLs=["https://example.com"],
)
client_id = client["UserPoolClient"]["ClientId"]
username = str(uuid.uuid4())
temporary_password = "1TemporaryP@ssword"
cognito.admin_create_user(
UserPoolId=user_pool_id,
Username=username,
TemporaryPassword=temporary_password,
)
result = cognito.admin_initiate_auth(
UserPoolId=user_pool_id,
ClientId=client_id,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": temporary_password},
)
# A newly created user is forced to set a new password
# This sets a new password and logs the user in (creates tokens)
password = "1F@kePassword"
result = cognito.respond_to_auth_challenge(
Session=result["Session"],
ClientId=client_id,
ChallengeName="NEW_PASSWORD_REQUIRED",
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": password},
)
#
id_token = result["AuthenticationResult"]["IdToken"]
# Verify the KID header is present in the token, and corresponds to the KID supplied by the public JWT
verify_kid_header(id_token)
def verify_kid_header(token):
"""Verifies the kid-header is corresponds with the public key"""
headers = jwt.get_unverified_headers(token)
kid = headers["kid"]
key_index = -1
keys = fetch_public_keys()
for i in range(len(keys)):
if kid == keys[i]["kid"]:
key_index = i
break
if key_index == -1:
raise Exception("Public key (kid) not found in jwks.json")
def fetch_public_keys():
keys_url = "https://cognito-idp.us-west-2.amazonaws.com/someuserpoolid/.well-known/jwks.json"
response = requests.get(keys_url).json()
return response["keys"]