Habilitar SMS_MFA con Custom Authentication Challenge Lambda Triggers
Habilitar challenge name SMS_MFA con CUSTOM_CHALLENGE
Vamos a partir de la documentación que nos provee amazon sobre los triggers o disparadores que nos permiten cumstomizar nuestra app de autenticaciòn para que afronte diferentes retos a la hora de autenticar un usuario https://docs.aws.amazon.com/es_es/cognito/latest/developerguide/user-pool-lambda-challenge.html
Después de haber implementado nuestros triggers lambdas y conectados a nuestro cognito debemos habilitar el MFA a cognito y habilitar a un usuario de prueba.
- En la barra de navegación izquierda, elija MFA and verifications (MFA y verificaciones).
- Elija el estado de la MFA: Off (Desactivada), Optional (Opcional) o Required (Obligatoria).
- Elija Optional (Opcional) para habilitar MFA para cada usuario o si utiliza la autenticación flexible basada en riesgos. Para obtener más información sobre la autenticación flexible, consulte Adición de seguridad avanzada a un grupo de usuarios.
- Elija las opciones de segundo factor que desea admitir en la aplicación. Los usuarios pueden utilizar SMS text message (Mensaje de texto SMS) o Time-based One-time Password (Contraseña de un solo uso basada en el tiempo) como segundo factor. Recomendamos utilizar TOTP, que permite utilizar SMS como mecanismo de recuperación de contraseñas en lugar de como factor de autenticación.
- Si utiliza mensajes de texto SMS como segundo factor y no tiene un IAM rol de definido con este permiso, puede crear uno en la consola de . Elija Create role (Crear rol) para crear un IAM rol de que permita Amazon Cognito a enviar mensajes SMS a los usuarios en su nombre. Para obtener más información, consulte Roles de IAM.
- Elija Save changes.
- Habilitamos al usuario en cuestión MFA autenticamos
Nos Autenticamos
aws cognito-idp admin-initiate-auth --user-pool-id us-west-2_aaaaaaaaa --client-id 3n4b5urk1ft4fl3mg5e62d9ado --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=jane@example.com,PASSWORD=password
Después si todo sale bien amazon nos enviara el codigo de confirmación por SMS a nuestro teléfono y utilizamos la session anterior, y ejecutamos el siguiente código .
aws cognito-idp respond-to-auth-challenge \
--client-id YOUR_COGNITO_APP_CLIENT_ID \
--challenge-name SMS_MFA \
--challenge-responses USERNAME=user@example.com,SMS_MFA_CODE=345678 \
--session "LONG_SESSION_STRING"
Después de ejecutar nuestro codigo nos retorne que no esta autorizado o que error en usuario o contraseña .
Esto sucede porque en el cognito que crea los desafíos tu no tiene contemplado la session de MFA .
Este es nuestro código por defecto de nuestro triggre Define Auth Challenge
exports.handler = (event, context, callback) => {
if (event.request.session.length == 1 && event.request.session[0].challengeName == 'SRP_A') {
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'PASSWORD_VERIFIER';
} else if (event.request.session.length == 2 && event.request.session[1].challengeName == 'PASSWORD_VERIFIER' && event.request.session[1].challengeResult == true) {
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
} else if (event.request.session.length == 3 && event.request.session[2].challengeName == 'CUSTOM_CHALLENGE' && event.request.session[2].challengeResult == true) {
event.response.issueTokens = true;
event.response.failAuthentication = false;
} else {
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
// Return to Amazon Cognito
callback(null, event);
}
Lo vamos a modificar para que nos soporte MFA y nos dispare el siguiente reto
...
// validar que venga un challengeName de tipo SMS_MFA valido
else if (event.request.session.length == 3 &&
event.request.session[1].challengeName == 'PASSWORD_VERIFIER' &&
event.request.session[2].challengeName == 'SMS_MFA' && event.request.session[2].challengeResult == true) {
event.response.issueTokens = false;
event.response.failAuthentication = false;
}
.....
y por ultimo agregar también la validación para que me soporte CUSTOM_CHALLENGE cuando a pasado por MFA
...
// validar que venga un challengeName de tipo CUSTOM_CHALLENGE valido
else if (event.request.session.length == 4 &&
event.request.session[2].challengeName == 'SMS_MFA' &&
event.request.session[3].challengeName == 'CUSTOM_CHALLENGE' && event.request.session[3].challengeResult == true) {
event.response.issueTokens = true;
event.response.failAuthentication = false;
}
.....
el código final
exports.handler = (event, context, callback) => {
if (event.request.session.length == 1 && event.request.session[0].challengeName == 'SRP_A') {
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'PASSWORD_VERIFIER';
} else if (event.request.session.length == 2 && event.request.session[1].challengeName == 'PASSWORD_VERIFIER' && event.request.session[1].challengeResult == true) {
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
} else if (event.request.session.length == 3 && event.request.session[2].challengeName == 'CUSTOM_CHALLENGE' && event.request.session[2].challengeResult == true) {
event.response.issueTokens = true;
event.response.failAuthentication = false;
}
// validar que venga un challengeName de tipo SMS_MFA valido
else if (event.request.session.length == 3 &&
event.request.session[1].challengeName == 'PASSWORD_VERIFIER' &&
event.request.session[2].challengeName == 'SMS_MFA' && event.request.session[2].challengeResult == true) {
event.response.issueTokens = false;
event.response.failAuthentication = false;
}
// validar que venga un challengeName de tipo CUSTOM_CHALLENGE valido
else if (event.request.session.length == 4 &&
event.request.session[2].challengeName == 'SMS_MFA' &&
event.request.session[3].challengeName == 'CUSTOM_CHALLENGE' && event.request.session[3].challengeResult == true) {
event.response.issueTokens = true;
event.response.failAuthentication = false;
}
} else {
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
// Return to Amazon Cognito
callback(null, event);
}
Actualizamos nuestro lambda y volveríamos a probar ejecutando con respond-to-auth-challenge con challenge-name SMS_MFA y después con CUSTOM_CHALLENGE el cual es el único que habilitamos para que nos retorne los tokens.
Happy code .
References: