Как изменить статус пользователя FORCE_CHANGE_PASSWORD?


97

Используя AWS Cognito, я хочу создать фиктивных пользователей для целей тестирования.

Затем я использую Консоль AWS для создания такого пользователя, но у пользователя есть его статус набор для FORCE_CHANGE_PASSWORD. С этим значением этот пользователь не может быть аутентифицирован.

Есть ли способ изменить этот статус?

ОБНОВЛЕНИЕ Такое же поведение при создании пользователя из CLI


1
Ответ пользователя предоставлен @joe
donlys

Ответы:


15

Извините, у вас возникли трудности. У нас нет одноэтапного процесса, в котором вы можете просто создавать пользователей и напрямую их аутентифицировать. Мы можем изменить это в будущем, чтобы позволить администраторам устанавливать пароли, которые будут напрямую использоваться пользователями. На данный момент, когда вы создаете пользователей с помощью AdminCreateUserили путем регистрации пользователей в приложении, требуются дополнительные шаги: либо принуждение пользователей к смене пароля при входе в систему, либо подтверждение пользователями электронной почты или номера телефона для изменения статуса пользователя на CONFIRMED.


4
На данный момент, когда вы создаете пользователей либо с помощью AdminCreateUser, либо путем регистрации пользователей в приложении, требуются дополнительные шаги: либо принуждение пользователей к смене пароля при входе в систему, либо проверка пользователями электронной почты или номера телефона для изменения статуса пользователя на ПОДТВЕРЖДЕНО. Что именно это за дополнительные усилия и как их запустить из JS SDK.
Саураб Тивари

3
@joe указал, что теперь это возможно, поскольку оно было добавлено. ищите --permanentфлаг: stackoverflow.com/a/56948249/3165552
isaias-b

149

Я знаю, что прошло много времени, но подумал, что это может помочь другим людям, которые натолкнулись на этот пост.

Вы можете использовать AWS CLI для изменения пароля пользователя, однако это многоступенчатый процесс:


Шаг 1. Получите токен сеанса для нужного пользователя:

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%

Если это возвращает ошибку about Unable to verify secret hash for client, создайте другой клиент приложения без секрета и используйте этот идентификатор клиента.

Шаг 2: Если шаг 1 прошел успешно, он ответит запросом NEW_PASSWORD_REQUIRED, другими параметрами запроса и ключом сеанса пользователя. Затем вы можете запустить вторую команду, чтобы выдать ответ на запрос:

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 ""%

Если вы получаете сообщение об ошибке Invalid attributes given, XXX is missingпередачи недостающих атрибутов в форматеuserAttributes.$FIELD_NAME=$VALUE

Приведенная выше команда должна возвращать действительный результат аутентификации и соответствующие токены.


Важно: для того, чтобы это работало, пул пользователей Cognito ДОЛЖЕН иметь клиент приложения, настроенный с ADMIN_NO_SRP_AUTHфункциональными возможностями ( шаг 5 в этом документе ).


24
Удивительно полезно. Еще два совета: если вы получаете сообщение об ошибке «Невозможно проверить секретный хэш для клиента», создайте другое приложение-клиент без секрета и используйте его ( stackoverflow.com/questions/37438879/… ). Если вы получаете сообщение об ошибке «Указаны недопустимые атрибуты, отсутствует XXX», передайте недостающие атрибуты в формате userAttributes.$FIELD_NAME=$VALUE( github.com/aws/aws-sdk-js/issues/1290 ).
Лейн Реттиг

Если вы не можете вывести пользователя из FORCE_CHANGE_PASSWORD с помощью любой из команд CLI (включая этот ответ), попробуйте «admin-disable-user», затем «admin-enable-user» или используйте консоль. Затем либо воспользуйтесь этим процессом, либо вы сможете использовать обычный процесс сброса пароля. Иногда у пользователя истекает срок действия, если он не вошел в когнитивную систему в пределах установленного лимита. (по умолчанию 7 дней, я думаю)
comfytoday

Пробовал с помощью CLI и внутри лямбды, получил эту ошибку: указаны недопустимые атрибуты, имя отсутствует
kolodi

1
@misher вы получаете это из-за обязательных атрибутов. вы можете включить их в вызов, но синтаксис немного странный:--challenge-responses NEW_PASSWORD=password,USERNAME=username,userAttributes.picture=picture,userAttributes.name=name
edzillion

88

Наконец, это было добавлено в AWSCLI: https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/admin-set-user-password.html

Вы можете изменить пароль пользователя и статус обновления, используя:

aws cognito-idp admin-set-user-password --user-pool-id <your user pool id> --username user1 --password password --permanent

Перед использованием вам может потребоваться обновить интерфейс командной строки AWS, используя:

pip3 install awscli --upgrade


13
Это новейшее и самое эффективное решение!
donlys

7
Это должен быть ответ.
Мистер Янг

4
Лучшее и простое решение в 2020 году. Спасибо!
tudor

23

Просто добавьте этот код после вашего onSuccess: function (result) { ... },в вашей функции входа в систему. После этого у вашего пользователя будет статус ПОДТВЕРЖДЕН .

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
У меня это работает. Вы даже можете передать текущий пароль, если не хотите его менять.
mvandillen

Рекурсия FTW! Благодарность! (рекурсия - это thisполный вызов нового пароля)
Paul S

22

Вы можете изменить этот статус пользователя FORCE_CHANGE_PASSWORD, вызвав respondToAuthChallenge()его следующим образом:

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

После этого вы увидите в консоли user3статус CONFIRMED.


1
Я не понимаю, как ты сюда попал. Что вы звонили, чтобы получить сеанс, который вы прошли XXX? Когда я вызываю adminInitiateAuth, я получаю сообщение об ошибке UserNotFoundException.
Райан Шиллингтон

3
Извините, если этот ответ не был кристально ясным. Вот более подробная информация: 1. В пользовательском пуле есть клиент с именем your_own3j63rs8j16bxxxsto25db00obh, который создается БЕЗ сгенерированного секретного ключа. Приведенный выше код не будет работать, если клиенту назначен ключ. 2) Ключ сеанса - это значение, возвращаемое при звонкеcognitoidentityserviceprovider.adminInitiateAuth({ AuthFlow: 'ADMIN_NO_SRP_AUTH', ClientId: 'your_own3j63rs8j16bxxxsto25db00obh', UserPoolId: 'us-east-1_DtNSUVT7n', AuthParameters: { USERNAME: 'user3', PASSWORD: 'original_password' } }, callback);
Ариэль Араза,

3) user3был создан в консоли и изначально получил пароль'original_password'
Ariel

ОК. Теперь я понимаю, почему я получал исключение UserNotFoundException. Это произошло потому, что я использовал псевдоним в качестве имени пользователя для входа в систему, который отлично работает в JS API, но, по-видимому, не работает с adminInitiateAuth. Спасибо, Ариэль Араза, ценю вашу помощь.
Райан Шиллингтон

Ура! Наконец-то я заставил это работать. Спасибо! Спасибо, Ариэль!
Райан Шиллингтон

11

не уверен, что вы все еще боретесь с этим, но для создания группы тестовых пользователей я использовал awscliкак таковой:

  1. Используйте подкоманду регистрации из когнито-idp, чтобы создать пользователя
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%
  1. Подтвердите пользователя с помощью admin-confirm-sign-up
aws cognito-idp admin-confirm-sign-up \
--user-pool-id %aws_user_pools_web_client_id% \
--username %email_address%

5

ОБНОВИТЬ:

Теперь я использую это, переведенное для усиления, внутри 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);
      });
  });
};

Я устанавливаю временный пароль, а затем сбрасываю его на пароль, запрошенный пользователем.

СТАРЫЙ ПОЧТ:

Вы можете решить эту проблему с помощью SDK amazon-cognito-identity-js, аутентифицируясь с временным паролем после создания учетной записи cognitoidentityserviceprovider.adminCreateUser()и выполняя ее cognitoUser.completeNewPasswordChallenge()внутри cognitoUser.authenticateUser( ,{newPasswordRequired})- все внутри функции, которая создает вашего пользователя.

Я использую приведенный ниже код внутри AWS lambda для создания включенных учетных записей пользователей Cognito. Я уверен, что его можно оптимизировать, наберитесь терпения. Это мой первый пост, и я все еще новичок в 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 });
    });

@Tom - у тебя работает? что я могу уточнить?
qqan.ny

Теперь гораздо лучше.
Том Аранда

@ qqan.ny использует обещания и обратные вызовы одновременно? Зачем?
Юрий Гольский

@Iurii Golskyi - тогда я не знал лучшего, только начал изучать AWS и JS с нуля.
qqan.ny 01

4

Для Java SDK, предполагая, что ваш клиент Cognito настроен и у вас есть пользователь в состоянии FORCE_CHANGE_PASSWORD, вы можете сделать следующее, чтобы получить ПОДТВЕРЖДЕНИЕ вашего пользователя ... и затем авторизоваться как обычно.

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

Надеюсь, это поможет с этими интеграционными тестами (извините за форматирование)


4

По сути, это тот же ответ, но для .Net C # SDK:

Следующее приведет к созданию полного администратора с желаемым именем пользователя и паролем. Имея следующую модель пользователя:

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Вы можете создать пользователя и подготовить его к использованию, используя:

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

3

Если вы пытаетесь изменить статус администратора из консоли. Затем выполните следующие шаги после создания пользователя.

  1. В Cognito goto -> «управлять пулом пользователей» ->
  2. Перейдите в «Настройки клиента приложения» в разделе «Интеграция приложений».
  3. Проверьте следующие пункты: i) Пул пользователей Cognito ii) Предоставление кода авторизации iii) Неявное разрешение iv) телефон v) электронная почта vi) openid vii) aws.cognito.signin.user.admin viii) профиль
  4. Введите URL-адрес обратного вызова вашего приложения. Если вы не уверены, введите, например: https://google.com и позже, вы можете изменить его на свой фактический URL-адрес обратного вызова.
  5. нажмите «Сохранить изменения».
  6. После сохранения изменений щелкните ссылку «Запустить размещенный интерфейс».
  7. Введите учетные данные нового созданного пользователя
  8. Сбросьте пароль с новыми учетными данными и поделитесь ими с пользователем

шаг 2

шаг 3 4 5 6

шаг 7

шаг 8


2

Я знаю, что это тот же ответ, но подумал, что это может помочь Goсообществу разработчиков. в основном это инициирует запрос аутентификации, получает сеанс и отвечает на запрос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 
}

Вот модульный тест:

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)

        })

    })
}

1

ОК. Наконец-то у меня есть код, в котором администратор может создать нового пользователя. Процесс выглядит так:

  1. Админ создает пользователя
  2. Пользователь получает электронное письмо со своим временным паролем
  3. Пользователь входит в систему и его просят сменить пароль

Шаг 1 - самая сложная часть. Вот мой код для создания пользователя в 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);
      }
    });
  }
});

По сути, вам нужно отправить вторую команду, чтобы письмо считалось проверенным. Пользователю по-прежнему необходимо перейти на свою электронную почту, чтобы получить временный пароль (который также проверяет электронную почту). Но без этого второго вызова, который устанавливает подтверждение электронной почты, вы не получите ответный звонок для сброса пароля.


Я все еще не получаю электронное письмо, есть предложения?
Vinicius

Странно, вы правильно настроили адрес электронной почты в Cognito, с доступом к SES и т. Д.? Cogntio не будет просто отправлять электронные письма людям, пока вы не подтвердите адрес электронной почты, на который пытаетесь отправить, или пока вы не получите одобрение на отправку кому-либо.
Райан Шиллингтон

Я получаю сообщения электронной почты с кодом подтверждения, значит, настройки верны. Просто электронное письмо с временным паролем никогда не приходит ... В итоге я создал лямбду, прикрепленную к триггеру предварительной регистрации, чтобы отправить электронное письмо.
Vinicius
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.