132 votes

Comment changer le statut de l'utilisateur FORCE_CHANGE_PASSWORD ?

En utilisant AWS Cognito, je veux créer des utilisateurs fictifs à des fins de test.

J'utilise ensuite le Console AWS pour créer un tel utilisateur, mais l'utilisateur a sa propre statut réglé sur FORCE_CHANGE_PASSWORD . Avec cette valeur, cet utilisateur ne peut pas être authentifié.

Y a-t-il un moyen de modifier ce statut ?

UPDATE Même comportement lors de la création d'un utilisateur à partir du CLI

2 votes

Réponse de l'utilisateur fournie par @joe

159voto

Neutral Penguin Points 881

Je sais que cela fait un moment mais j'ai pensé que cela pourrait aider d'autres personnes qui tombent sur ce post.

Vous pouvez utiliser l'AWS CLI pour modifier le mot de passe des utilisateurs, mais il s'agit d'un processus en plusieurs étapes :


Étape 1 : Obtenir un jeton de session pour l'utilisateur souhaité :

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 cela renvoie une erreur concernant Unable to verify secret hash for client , créer un autre client d'application sans secret et utiliser cet identifiant client.

Étape 2 : Si l'étape 1 est réussie, il répondra avec le défi NEW_PASSWORD_REQUIRED les autres paramètres du défi et la clé de session de l'utilisateur. Ensuite, vous pouvez exécuter la deuxième commande pour émettre la réponse au défi :

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 vous obtenez une erreur concernant Invalid attributes given, XXX is missing transmettre les attributs manquants en utilisant le format userAttributes.$FIELD_NAME=$VALUE

La commande ci-dessus devrait renvoyer un résultat d'authentification valide et les jetons appropriés.


Important : Pour que cela fonctionne, le pool d'utilisateurs de Cognito DOIT avoir un numéro d'identification de l'utilisateur. Client de l'application configuré avec ADMIN_NO_SRP_AUTH fonctionnalité ( Étape 5 dans ce document ).

26 votes

Étonnamment utile. Deux autres conseils : si vous obtenez une erreur du type "Impossible de vérifier le hachage du secret pour le client", créez une autre application client sans secret et utilisez-la ( stackoverflow.com/questions/37438879/ ). Si vous obtenez une erreur du type "Invalid attributes given, XXX is missing", indiquez les attributs manquants en utilisant le format suivant userAttributes.$FIELD_NAME=$VALUE ( github.com/aws/aws-sdk-js/issues/1290 ).

0 votes

Si vous ne parvenez pas à sortir votre utilisateur de FORCE_CHANGE_PASSWORD, avec l'une des commandes CLI (y compris cette réponse), essayez 'admin-disable-user' puis 'admin-enable-user' ou utilisez la console. Ensuite, vous pouvez soit utiliser ce processus, soit utiliser le flux normal de réinitialisation du mot de passe. Parfois, un utilisateur va "expirer" s'il ne s'est pas connecté à Cognito dans la limite prédéfinie. (par défaut 7 jours je pense)

0 votes

J'ai essayé avec le CLI et dans un lambda, j'ai eu cette erreur : Attributs invalides donnés, le nom est manquant

24voto

Baked Inhalf Points 165

Il suffit d'ajouter ce code après votre onSuccess: function (result) { ... }, dans votre fonction de connexion. Votre utilisateur aura alors le statut CONFIRMÉ .

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);
}

1 votes

Cela fonctionne pour moi. Vous pouvez même indiquer le mot de passe actuel si vous ne voulez pas le changer.

0 votes

Récursion FTW ! Merci ! (la récursion est la this sur le nouveau défi complet du mot de passe)

22voto

Ariel Araza Points 151

Vous pouvez modifier ce statut d'utilisateur FORCE_CHANGE_PASSWORD en appelant respondToAuthChallenge() sur l'utilisateur comme ceci :

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
});

Après cela, vous verrez dans la console que user3 Le statut est CONFIRMED .

1 votes

Je ne comprends pas comment vous êtes arrivé ici. Qu'avez-vous appelé pour obtenir la session que vous avez XXX ? Lorsque j'appelle adminInitiateAuth, je reçois une erreur disant UserNotFoundException.

3 votes

Désolé si cette réponse n'était pas très claire. Voici plus de détails : 1. Le pool d'utilisateurs a un client appelé 'your_own3j63rs8j16bxxxsto25db00obh' qui est créé SANS clé secrète générée. Le code ci-dessus ne fonctionnera pas si une clé est attribuée au client. 2) La clé de session est la valeur retournée par l'appel à cognitoidentityserviceprovider.adminInitiateAuth({ AuthFlow: 'ADMIN_NO_SRP_AUTH', ClientId: 'your_own3j63rs8j16bxxxsto25db00obh', UserPoolId: 'us-east-1_DtNSUVT7n', AuthParameters: { USERNAME: 'user3', PASSWORD: 'original_password' } }, callback);

0 votes

3) user3 a été créé dans la console et a reçu initialement le mot de passe 'original_password'

17voto

Ionut Trestian Points 2393

Désolé que vous ayez des difficultés. Nous ne disposons pas d'un processus en une seule étape permettant de créer des utilisateurs et de les authentifier directement. Nous pourrions changer cela à l'avenir, par exemple pour permettre aux administrateurs de définir des mots de passe directement utilisables par les utilisateurs. Pour l'instant, lorsque vous créez des utilisateurs, soit en utilisant AdminCreateUser ou en inscrivant les utilisateurs à l'application, des étapes supplémentaires sont requises, soit en forçant les utilisateurs à changer le mot de passe lors de la connexion, soit en demandant aux utilisateurs de vérifier l'email ou le numéro de téléphone pour changer le statut de l'utilisateur en CONFIRMED .

4 votes

Pour l'instant, lorsque vous créez des utilisateurs à l'aide de AdminCreateUser ou en inscrivant des utilisateurs avec l'application, des étapes supplémentaires sont requises, soit en forçant les utilisateurs à changer le mot de passe lors de la connexion, soit en demandant aux utilisateurs de vérifier l'e-mail ou le numéro de téléphone pour changer le statut de l'utilisateur en CONFIRMÉ. Quels sont exactement ces efforts supplémentaires et comment puis-je les déclencher à partir du SDK JS ?

4 votes

@joe a fait remarquer que c'est maintenant possible, depuis qu'il a été ajouté. recherchez l'élément --permanent drapeau : stackoverflow.com/a/56948249/3165552

8voto

qqan.ny Points 31

UPDATE :

Il y a eu quelques mises à jour, et le client Amplify n'est plus nécessaire. Après adminCreateUser(), vous pouvez maintenant juste utiliser

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]

ceci définira l'utilisateur comme "confirmé".

UPDATE :

Je l'utilise maintenant, traduit pour amplifier, dans un Lambda NodeJS :

// 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);
      });
  });
};

Je définis un mot de passe temporaire et je le réinitialise plus tard avec le mot de passe demandé par l'utilisateur.

OLD POST :

Vous pouvez résoudre ce problème en utilisant le SDK amazon-cognito-identity-js en vous authentifiant avec le mot de passe temporaire après la création du compte avec cognitoidentityserviceprovider.adminCreateUser() et en cours d'exécution cognitoUser.completeNewPasswordChallenge() sur cognitoUser.authenticateUser( ,{newPasswordRequired}) - tout cela dans la fonction qui crée votre utilisateur.

J'utilise le code ci-dessous dans AWS lambda pour créer des comptes d'utilisateurs Cognito. Je suis sûr qu'il peut être optimisé, soyez patient avec moi. C'est mon premier message, et je suis encore assez novice 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, e.g. email to new user
                    resolve(finalResult);
                })
                .catch(err => {
                    reject(err);
                });
        });
        return anotherPromise;
    })
    .then(() => {
        resolve(finalResult);
    })
    .catch(err => {
        reject({ statusCode: 406, error: err });
    });

0 votes

@Tom - est-ce que ça marche pour vous ? Quelque chose que je peux clarifier ?

0 votes

Beaucoup mieux maintenant.

0 votes

@qqan.ny utiliser des promesses et des callbacks en même temps ? Pourquoi ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X