Con AWS Cognito, quiero crear usuarios ficticios con fines de prueba.
Luego uso la consola de AWS para crear dicho usuario, pero el usuario tiene su estado establecido en FORCE_CHANGE_PASSWORD . Con ese valor, este usuario no puede ser autenticado.
¿Hay alguna manera de cambiar este estado?
ACTUALIZAR Mismo comportamiento al crear un usuario desde CLI
He estado muchas veces en la misma situación. Por lo tanto, escribió una CLI pequeña en golang para autenticar exactamente como usuario (para fines de prueba adicionales) o simplemente restablecer administrativamente el pase.
Entonces todo lo que ejecutas como comando es
$ > go-cognito-authy --profile cloudy -region eu-central-1 admin reset-pass --username rafpe --pass-new 'Password.0ne2!' --clientID 2jxxxiuui123 --userPoolID eu-central-1_CWNnTiR0j --session "bCqSkLeoJR_ys...."La solución está disponible en github https://github.com/RafPe/go-cognito-authy/tree/master
Si está intentando cambiar el estado como administrador desde la consola. Luego, siga los pasos a continuación después de crear el usuario.
Esto finalmente se agregó a AWSCLI: https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/admin-set-user-password.html
Puede cambiar la contraseña de un usuario y actualizar el estado usando:
aws cognito-idp admin-set-user-password \ --user-pool-id <your-user-pool-id> \ --username <username> \ --password <password> \ --permanentAntes de usar esto, es posible que deba actualizar su AWS CLI usando:
pip3 install awscli --upgrade
Puede cambiar ese estado de usuario FORCE_CHANGE_PASSWORD llamando a respondToAuthChallenge() en el usuario de esta manera:
var params = { ChallengeName: 'NEW_PASSWORD_REQUIRED', ClientId: 'your_own3j6...0obh', ChallengeResponses: { USERNAME: 'user3', NEW_PASSWORD: 'changed12345' }, Session: 'xxxxxxxxxxZDMcRu-5u...sCvrmZb6tHY' }; cognitoidentityserviceprovider.respondToAuthChallenge(params, function(err, data) { if (err) console.log(err, err.stack); // an error occurred else console.log(data); // successful response });Después de esto, verá en la consola que el estado de
user3esCONFIRMED.
Lamento que estés teniendo dificultades. No tenemos un proceso de un solo paso en el que solo puede crear usuarios y autenticarlos directamente. Podríamos cambiar esto en el futuro, por ejemplo, para permitir que los administradores establezcan contraseñas que los usuarios puedan usar directamente. Por ahora, cuando crea usuarios usando AdminCreateUser o registrando usuarios con la aplicación, se requieren pasos adicionales, ya sea obligando a los usuarios a cambiar la contraseña al iniciar sesión o haciendo que los usuarios verifiquen el correo electrónico o el número de teléfono para cambiar el estado del usuario a CONFIRMED .
Sé que ha pasado un tiempo, pero pensé que esto podría ayudar a otras personas que se encuentran con esta publicación.
Puede utilizar la AWS CLI para cambiar la contraseña de los usuarios, sin embargo, es un proceso de varios pasos:
Paso 1: obtenga un token de sesión para el usuario deseado:
aws cognito-idp admin-initiate-auth --user-pool-id %USER POOL ID% --client-id %APP CLIENT ID% --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=%USERS USERNAME%,PASSWORD=%USERS CURRENT PASSWORD%Si esto devuelve un error sobre
Unable to verify secret hash for client, cree otro cliente de aplicación sin un secreto y use esa ID de cliente.
Paso 2: si el paso 1 es exitoso, responderá con el desafío NEW_PASSWORD_REQUIRED , otros parámetros de desafío y la clave de sesión de los usuarios. Luego, puede ejecutar el segundo comando para emitir la respuesta de desafío:
aws cognito-idp admin-respond-to-auth-challenge --user-pool-id %USER POOL ID% --client-id %CLIENT ID% --challenge-name NEW_PASSWORD_REQUIRED --challenge-responses NEW_PASSWORD=%DESIRED PASSWORD%,USERNAME=%USERS USERNAME% --session %SESSION KEY FROM PREVIOUS COMMAND with ""%Si obtiene un error acerca de los
Invalid attributes given, XXX is missingpase los atributos faltantes usando el formatouserAttributes.$FIELD_NAME=$VALUE
El comando anterior debe devolver un resultado de autenticación válido y tokens apropiados.
Importante: Para que esto funcione, el grupo de usuarios de Cognito DEBE tener un cliente de aplicación configurado con la funcionalidad ADMIN_NO_SRP_AUTH ( Paso 5 en este documento ).
está bien. Finalmente tengo un código donde un administrador puede crear un nuevo usuario. El proceso es así:
El paso 1 es la parte difícil. Aquí está mi código para crear un usuario en Node JS:
let params = { UserPoolId: "@cognito_pool_id@", Username: username, DesiredDeliveryMediums: ["EMAIL"], ForceAliasCreation: false, UserAttributes: [ { Name: "given_name", Value: firstName }, { Name: "family_name", Value: lastName}, { Name: "name", Value: firstName + " " + lastName}, { Name: "email", Value: email}, { Name: "custom:title", Value: title}, { Name: "custom:company", Value: company + ""} ], }; let cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider(); cognitoIdentityServiceProvider.adminCreateUser(params, function(error, data) { if (error) { console.log("Error adding user to cognito: " + error, error.stack); reject(error); } else { // Uncomment for interesting but verbose logging... //console.log("Received back from cognito: " + CommonUtils.stringify(data)); cognitoIdentityServiceProvider.adminUpdateUserAttributes({ UserAttributes: [{ Name: "email_verified", Value: "true" }], UserPoolId: "@cognito_pool_id@", Username: username }, function(err) { if (err) { console.log(err, err.stack); } else { console.log("Success!"); resolve(data); } }); } });Básicamente, debe enviar un segundo comando para forzar que el correo electrónico se considere verificado. El usuario aún debe ir a su correo electrónico para obtener la contraseña temporal (que también verifica el correo electrónico). Pero sin esa segunda llamada que configura el correo electrónico como verificado, no recibirás la llamada correcta para restablecer su contraseña.
Simplemente agregue este código después de su onSuccess: function (result) { ... }, dentro de su función de inicio de sesión. Su usuario tendrá entonces el estado CONFIRMADO .
newPasswordRequired: function(userAttributes, requiredAttributes) { // User was signed up by an admin and must provide new // password and required attributes, if any, to complete // authentication. // the api doesn't accept this field back delete userAttributes.email_verified; // unsure about this field, but I don't send this back delete userAttributes.phone_number_verified; // Get these details and call cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this); }ACTUALIZAR:
Ha habido algunas actualizaciones y ya no se necesita el cliente Amplify. Después de adminCreateUser(), ahora puede simplemente usar
cisp.adminSetUserPassword({ UserPoolId: pool_id, Username: login, Password: password, Permanent: true })[https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminSetUserPassword.html]
esto configurará al usuario como "confirmado".
ACTUALIZAR:
Ahora estoy usando esto, traducido para amplificar, dentro de un NodeJS Lambda:
// enable node-fetch polyfill for Node.js global.fetch = require("node-fetch").default; global.navigator = {}; const AWS = require("aws-sdk"); const cisp = new AWS.CognitoIdentityServiceProvider(); const Amplify = require("@aws-amplify/core").default; const Auth = require("@aws-amplify/auth").default; ... /* this_user: { given_name: string, password: string, email: string, cell: string } */ const create_cognito = (this_user) => { let this_defaults = { password_temp: Math.random().toString(36).slice(-8), password: this_user.password, region: global._env === "prod" ? production_region : development_region, UserPoolId: global._env === "prod" ? production_user_pool : development_user_pool, ClientId: global._env === "prod" ? production_client_id : development_client_id, given_name: this_user.given_name, email: this_user.email, cell: this_user.cell, }; // configure Amplify Amplify.configure({ Auth: { region: this_defaults.region, userPoolId: this_defaults.UserPoolId, userPoolWebClientId: this_defaults.ClientId, }, }); if (!Auth.configure()) return Promise.reject("could not configure amplify"); return new Promise((resolve, reject) => { let _result = {}; let this_account = undefined; let this_account_details = undefined; // create cognito account cisp .adminCreateUser({ UserPoolId: this_defaults.UserPoolId, Username: this_defaults.given_name, DesiredDeliveryMediums: ["EMAIL"], ForceAliasCreation: false, MessageAction: "SUPPRESS", TemporaryPassword: this_defaults.password_temp, UserAttributes: [ { Name: "given_name", Value: this_defaults.given_name }, { Name: "email", Value: this_defaults.email }, { Name: "phone_number", Value: this_defaults.cell }, { Name: "email_verified", Value: "true" }, ], }) .promise() .then((user) => { console.warn(".. create_cognito: create.."); _result.username = user.User.Username; _result.temporaryPassword = this_defaults.password_temp; _result.password = this_defaults.password; // sign into cognito account return Auth.signIn(_result.username, _result.temporaryPassword); }) .then((user) => { console.warn(".. create_cognito: signin.."); // complete challenge return Auth.completeNewPassword(user, _result.password, { email: this_defaults.email, phone_number: this_defaults.cell, }); }) .then((user) => { console.warn(".. create_cognito: confirmed.."); this_account = user; // get details return Auth.currentAuthenticatedUser(); }) .then((this_details) => { if (!(this_details && this_details.attributes)) throw "account creation failes"; this_account_details = Object.assign({}, this_details.attributes); // signout return this_account.signOut(); }) .then(() => { console.warn(".. create_cognito: complete"); resolve(this_account_details); }) .catch((err) => { console.error(".. create_cognito: error"); console.error(err); reject(err); }); }); };Estoy configurando una contraseña temporal y luego la restablezco a la contraseña solicitada por el usuario.
POSTE ANTIGUO:
Puede resolver esto usando el SDK de amazon-cognito-identity-js autenticándose con la contraseña temporal después de la creación de la cuenta con cognitoidentityserviceprovider.adminCreateUser() y ejecutando cognitoUser.completeNewPasswordChallenge() dentro de cognitoUser.authenticateUser( ,{newPasswordRequired}) - all dentro de la función que crea su usuario.
Estoy usando el siguiente código dentro de AWS lambda para crear cuentas de usuario de Cognito habilitadas. Estoy seguro de que se puede optimizar, tenga paciencia conmigo. Esta es mi primera publicación, y todavía soy bastante nuevo en JavaScript.
var AWS = require("aws-sdk"); var AWSCognito = require("amazon-cognito-identity-js"); var params = { UserPoolId: your_poolId, Username: your_username, DesiredDeliveryMediums: ["EMAIL"], ForceAliasCreation: false, MessageAction: "SUPPRESS", TemporaryPassword: your_temporaryPassword, UserAttributes: [ { Name: "given_name", Value: your_given_name }, { Name: "email", Value: your_email }, { Name: "phone_number", Value: your_phone_number }, { Name: "email_verified", Value: "true" } ] }; var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider(); let promise = new Promise((resolve, reject) => { cognitoidentityserviceprovider.adminCreateUser(params, function(err, data) { if (err) { reject(err); } else { resolve(data); } }); }); promise .then(data => { // login as new user and completeNewPasswordChallenge var anotherPromise = new Promise((resolve, reject) => { var authenticationDetails = new AWSCognito.AuthenticationDetails({ Username: your_username, Password: your_temporaryPassword }); var poolData = { UserPoolId: your_poolId, ClientId: your_clientId }; var userPool = new AWSCognito.CognitoUserPool(poolData); var userData = { Username: your_username, Pool: userPool }; var cognitoUser = new AWSCognito.CognitoUser(userData); let finalPromise = new Promise((resolve, reject) => { cognitoUser.authenticateUser(authenticationDetails, { onSuccess: function(authResult) { cognitoUser.getSession(function(err) { if (err) { } else { cognitoUser.getUserAttributes(function( err, attResult ) { if (err) { } else { resolve(authResult); } }); } }); }, onFailure: function(err) { reject(err); }, newPasswordRequired(userAttributes, []) { delete userAttributes.email_verified; cognitoUser.completeNewPasswordChallenge( your_newPoassword, userAttributes, this ); } }); }); finalPromise .then(finalResult => { // signout cognitoUser.signOut(); // further action, eg email to new user resolve(finalResult); }) .catch(err => { reject(err); }); }); return anotherPromise; }) .then(() => { resolve(finalResult); }) .catch(err => { reject({ statusCode: 406, error: err }); });Para el SDK de Java, suponiendo que su cliente de Cognito esté configurado y que su usuario esté en el estado FORCE_CHANGE_PASSWORD, puede hacer lo siguiente para que su usuario sea CONFIRMADO... y luego autenticado normalmente.
AdminCreateUserResult createUserResult = COGNITO_CLIENT.adminCreateUser(createUserRequest()); AdminInitiateAuthResult authResult = COGNITO_CLIENT.adminInitiateAuth(authUserRequest()); Map<String,String> challengeResponses = new HashMap<>(); challengeResponses.put("USERNAME", USERNAME); challengeResponses.put("NEW_PASSWORD", PASSWORD); RespondToAuthChallengeRequest respondToAuthChallengeRequest = new RespondToAuthChallengeRequest() .withChallengeName("NEW_PASSWORD_REQUIRED") .withClientId(CLIENT_ID) .withChallengeResponses(challengeResponses) .withSession(authResult.getSession()); COGNITO_CLIENT.respondToAuthChallenge(respondToAuthChallengeRequest);Espero que ayude con esas pruebas de integración (perdón por el formato)
No estoy seguro de si todavía está luchando con esto, pero solo para crear un grupo de usuarios de prueba, utilicé awscli como tal:
aws cognito-idp sign-up \ --region %aws_project_region% \ --client-id %aws_user_pools_web_client_id% \ --username %email_address% \ --password %password% \ --user-attributes Name=email,Value=%email_address% aws cognito-idp admin-confirm-sign-up \ --user-pool-id %aws_user_pools_web_client_id% \ --username %email_address%Básicamente, esta es la misma respuesta pero para .Net C# SDK:
Lo siguiente hará una creación de usuario administrador completo con el nombre de usuario y la contraseña deseados. Tener el siguiente modelo de Usuario:
public class User { public string Username { get; set; } public string Password { get; set; } }Puede crear un usuario y dejarlo listo para usar usando:
public void AddUser(User user) { var tempPassword = "ANY"; var request = new AdminCreateUserRequest() { Username = user.Username, UserPoolId = "MyuserPoolId", TemporaryPassword = tempPassword }; var result = _cognitoClient.AdminCreateUserAsync(request).Result; var authResponse = _cognitoClient.AdminInitiateAuthAsync(new AdminInitiateAuthRequest() { UserPoolId = "MyuserPoolId", ClientId = "MyClientId", AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH, AuthParameters = new Dictionary<string, string>() { {"USERNAME",user.Username }, {"PASSWORD", tempPassword} } }).Result; _cognitoClient.RespondToAuthChallengeAsync(new RespondToAuthChallengeRequest() { ClientId = "MyClientId", ChallengeName = ChallengeNameType.NEW_PASSWORD_REQUIRED, ChallengeResponses = new Dictionary<string, string>() { {"USERNAME",user.Username }, {"NEW_PASSWORD",user.Password } }, Session = authResponse.Session }); }Sé que es la misma respuesta, pero pensé que podría ayudar a la comunidad de desarrolladores de Go . básicamente es iniciar la solicitud de autenticación, obtener la sesión y responder al desafío NEW_PASSWORD_REQUIRED
func sessionWithDefaultRegion(region string) *session.Session { sess := Session.Copy() if v := aws.StringValue(sess.Config.Region); len(v) == 0 { sess.Config.Region = aws.String(region) } return sess } func (c *CognitoAppClient) ChangePassword(userName, currentPassword, newPassword string) error { sess := sessionWithDefaultRegion(c.Region) svc := cognitoidentityprovider.New(sess) auth, err := svc.AdminInitiateAuth(&cognitoidentityprovider.AdminInitiateAuthInput{ UserPoolId:aws.String(c.UserPoolID), ClientId:aws.String(c.ClientID), AuthFlow:aws.String("ADMIN_NO_SRP_AUTH"), AuthParameters: map[string]*string{ "USERNAME": aws.String(userName), "PASSWORD": aws.String(currentPassword), }, }) if err != nil { return err } request := &cognitoidentityprovider.AdminRespondToAuthChallengeInput{ ChallengeName: aws.String("NEW_PASSWORD_REQUIRED"), ClientId:aws.String(c.ClientID), UserPoolId: aws.String(c.UserPoolID), ChallengeResponses:map[string]*string{ "USERNAME":aws.String(userName), "NEW_PASSWORD": aws.String(newPassword), }, Session:auth.Session, } _, err = svc.AdminRespondToAuthChallenge(request) return err }Aquí hay una prueba unitaria:
import ( "fmt" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" . "github.com/smartystreets/goconvey/convey" "testing" ) func TestCognitoAppClient_ChangePassword(t *testing.T) { Convey("Testing ChangePassword!", t, func() { err := client.ChangePassword("user_name_here", "current_pass", "new_pass") Convey("Testing ChangePassword Results!", func() { So(err, ShouldBeNil) }) }) }