@@ -3294,6 +3294,7 @@ def user_authentication_flow(
32943294
32953295
32963296@cognitoidp_aws_verified (generate_secret = True , with_mfa = "ON" )
3297+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
32973298@pytest .mark .aws_verified
32983299def test_user_authentication_flow_mfa_on (user_pool = None , user_pool_client = None ):
32993300 conn = boto3 .client ("cognito-idp" , "us-west-2" )
@@ -3397,6 +3398,7 @@ def test_user_authentication_flow_mfa_on(user_pool=None, user_pool_client=None):
33973398
33983399
33993400@cognitoidp_aws_verified (generate_secret = True , with_mfa = "OPTIONAL" )
3401+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
34003402@pytest .mark .aws_verified
34013403def test_user_authentication_flow_mfa_optional (user_pool = None , user_pool_client = None ):
34023404 conn = boto3 .client ("cognito-idp" , "us-west-2" )
@@ -5019,6 +5021,7 @@ def test_initiate_auth_USER_PASSWORD_AUTH_with_FORCE_CHANGE_PASSWORD_status():
50195021
50205022
50215023@cognitoidp_aws_verified (explicit_auth_flows = ["USER_PASSWORD_AUTH" ], with_mfa = "ON" )
5024+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
50225025@pytest .mark .aws_verified
50235026def test_initiate_mfa_auth_USER_PASSWORD_AUTH_with_FORCE_CHANGE_PASSWORD_status (
50245027 user_pool = None , user_pool_client = None
@@ -5241,6 +5244,7 @@ def test_initiate_auth_with_invalid_secret_hash():
52415244
52425245
52435246@mock_aws
5247+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
52445248def test_setting_mfa ():
52455249 conn = boto3 .client ("cognito-idp" , "us-west-2" )
52465250
@@ -5329,6 +5333,7 @@ def test_admin_setting_single_mfa():
53295333
53305334
53315335@mock_aws
5336+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
53325337def test_admin_setting_mfa_totp_and_sms ():
53335338 conn = boto3 .client ("cognito-idp" , "us-west-2" )
53345339
@@ -5367,7 +5372,7 @@ def test_admin_setting_mfa_totp_and_sms():
53675372
53685373
53695374@mock_aws
5370- def test_admin_initiate_auth_when_token_totp_enabled ():
5375+ def test_admin_initiate_auth_when_token_totp_masked ():
53715376 conn = boto3 .client ("cognito-idp" , "us-west-2" )
53725377
53735378 result = authentication_flow (conn , "ADMIN_NO_SRP_AUTH" )
@@ -5425,6 +5430,123 @@ def test_admin_initiate_auth_when_token_totp_enabled():
54255430 assert result ["AuthenticationResult" ]["TokenType" ] == "Bearer"
54265431
54275432
5433+ @mock_aws
5434+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
5435+ def test_admin_initiate_auth_when_token_totp_enabled ():
5436+ conn = boto3 .client ("cognito-idp" , "us-west-2" )
5437+
5438+ result = authentication_flow (conn , "ADMIN_NO_SRP_AUTH" )
5439+ access_token = result ["access_token" ]
5440+ user_pool_id = result ["user_pool_id" ]
5441+ username = result ["username" ]
5442+ client_id = result ["client_id" ]
5443+ password = result ["password" ]
5444+ resp = conn .associate_software_token (AccessToken = access_token )
5445+ secret_code = resp ["SecretCode" ]
5446+ totp = pyotp .TOTP (secret_code )
5447+ user_code = totp .now ()
5448+ conn .verify_software_token (AccessToken = access_token , UserCode = user_code )
5449+
5450+ # Set MFA TOTP and SMS methods
5451+ conn .admin_set_user_mfa_preference (
5452+ Username = username ,
5453+ UserPoolId = user_pool_id ,
5454+ SoftwareTokenMfaSettings = {"Enabled" : True , "PreferredMfa" : True },
5455+ SMSMfaSettings = {"Enabled" : True , "PreferredMfa" : False },
5456+ )
5457+ result = conn .admin_get_user (UserPoolId = user_pool_id , Username = username )
5458+ assert len (result ["UserMFASettingList" ]) == 2
5459+ assert result ["PreferredMfaSetting" ] == "SOFTWARE_TOKEN_MFA"
5460+
5461+ # Initiate auth with TOTP
5462+ result = conn .admin_initiate_auth (
5463+ UserPoolId = user_pool_id ,
5464+ ClientId = client_id ,
5465+ AuthFlow = "ADMIN_NO_SRP_AUTH" ,
5466+ AuthParameters = {
5467+ "USERNAME" : username ,
5468+ "PASSWORD" : password ,
5469+ },
5470+ )
5471+
5472+ assert result ["ChallengeName" ] == "SOFTWARE_TOKEN_MFA"
5473+ assert result ["Session" ] != ""
5474+
5475+ # Respond to challenge with TOTP
5476+ result = conn .admin_respond_to_auth_challenge (
5477+ UserPoolId = user_pool_id ,
5478+ ClientId = client_id ,
5479+ ChallengeName = "SOFTWARE_TOKEN_MFA" ,
5480+ Session = result ["Session" ],
5481+ ChallengeResponses = {
5482+ "SOFTWARE_TOKEN_MFA_CODE" : totp .now (),
5483+ "USERNAME" : username ,
5484+ },
5485+ )
5486+
5487+ assert result ["AuthenticationResult" ]["IdToken" ] != ""
5488+ assert result ["AuthenticationResult" ]["AccessToken" ] != ""
5489+ assert result ["AuthenticationResult" ]["RefreshToken" ] != ""
5490+ assert result ["AuthenticationResult" ]["TokenType" ] == "Bearer"
5491+
5492+
5493+ @mock_aws
5494+ @mock .patch .dict (os .environ , {"MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP" : "true" })
5495+ def test_admin_initiate_auth_when_token_totp_enabled_invalid ():
5496+ conn = boto3 .client ("cognito-idp" , "us-west-2" )
5497+
5498+ result = authentication_flow (conn , "ADMIN_NO_SRP_AUTH" )
5499+ access_token = result ["access_token" ]
5500+ user_pool_id = result ["user_pool_id" ]
5501+ username = result ["username" ]
5502+ client_id = result ["client_id" ]
5503+ password = result ["password" ]
5504+ resp = conn .associate_software_token (AccessToken = access_token )
5505+ secret_code = resp ["SecretCode" ]
5506+ totp = pyotp .TOTP (secret_code )
5507+ user_code = totp .now ()
5508+ conn .verify_software_token (AccessToken = access_token , UserCode = user_code )
5509+
5510+ # Set MFA TOTP and SMS methods
5511+ conn .admin_set_user_mfa_preference (
5512+ Username = username ,
5513+ UserPoolId = user_pool_id ,
5514+ SoftwareTokenMfaSettings = {"Enabled" : True , "PreferredMfa" : True },
5515+ SMSMfaSettings = {"Enabled" : True , "PreferredMfa" : False },
5516+ )
5517+ result = conn .admin_get_user (UserPoolId = user_pool_id , Username = username )
5518+ assert len (result ["UserMFASettingList" ]) == 2
5519+ assert result ["PreferredMfaSetting" ] == "SOFTWARE_TOKEN_MFA"
5520+
5521+ # Initiate auth with TOTP
5522+ result = conn .admin_initiate_auth (
5523+ UserPoolId = user_pool_id ,
5524+ ClientId = client_id ,
5525+ AuthFlow = "ADMIN_NO_SRP_AUTH" ,
5526+ AuthParameters = {
5527+ "USERNAME" : username ,
5528+ "PASSWORD" : password ,
5529+ },
5530+ )
5531+
5532+ assert result ["ChallengeName" ] == "SOFTWARE_TOKEN_MFA"
5533+ assert result ["Session" ] != ""
5534+
5535+ with pytest .raises (ClientError ) as exc :
5536+ result = conn .admin_respond_to_auth_challenge (
5537+ UserPoolId = user_pool_id ,
5538+ ClientId = client_id ,
5539+ ChallengeName = "SOFTWARE_TOKEN_MFA" ,
5540+ Session = result ["Session" ],
5541+ ChallengeResponses = {
5542+ "SOFTWARE_TOKEN_MFA_CODE" : "123456" ,
5543+ "USERNAME" : username ,
5544+ },
5545+ )
5546+ err = exc .value .response ["Error" ]
5547+ assert err ["Code" ] == "CodeMismatch"
5548+
5549+
54285550@mock_aws
54295551def test_admin_initiate_auth_when_sms_mfa_enabled ():
54305552 conn = boto3 .client ("cognito-idp" , "us-west-2" )
0 commit comments