Как включить TOTP MFA в AWS процесс аутентификации Cognito - PullRequest
2 голосов
/ 15 января 2020

Я использую пулы пользователей Cognito для аутентификации моего веб-приложения. У меня все это работает прямо сейчас, но теперь мне нужно включить MFA для этого. Вот как я это делаю прямо сейчас (весь код предоставлен на стороне сервера):

  1. Регистрация пользователя:
const cognito = new AWS.CognitoIdentityServiceProvider();
cognito.signUp({
    ClientId,
    Username: email,
    Password,
}).promise();

На адрес пользователя отправляется электронное письмо (упомянутое как имя пользователя в предыдущем вызове функции) с кодом внутри.

Пользователь читает код и предоставляет код к следующему вызову функции:

cognito.confirmSignUp({
    ClientId,
    ConfirmationCode,
    Username: email,
    ForceAliasCreation: false,
}).promise();
Пользователь входит в систему:
const tokens = await cognito.adminInitiateAuth({
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    ClientId,
    UserPoolId,
    AuthParameters: {
        'USERNAME': email,
        'PASSWORD': password,
    },
}).promise();

Я очень доволен этим процессом. Но теперь мне нужно добавить функциональность TOTP MFA к этому. Может кто-нибудь сказать мне, как эти шаги будут изменены, если я хочу это сделать? Кстати, я знаю, что TOTP MFA должен быть включен для пула пользователей при его создании. Я просто спрашиваю, как это влияет на процесс регистрации / входа.

1 Ответ

2 голосов
/ 16 января 2020

Хорошо, я нашел способ сделать это сам. Должен сказать, что я не смог найти никакой документации по этому вопросу, поэтому используйте ее на свой страх и риск!

Конечно, этот процесс предполагает, что у вас есть пул пользователей с включенным MFA (я использовал TOTP MFA).

  1. Регистрация пользователя:
const cognito = new AWS.CognitoIdentityServiceProvider();
cognito.signUp({
    ClientId,
    Username: email,
    Password,
}).promise();

На адрес пользователя отправляется электронное письмо (упомянутое как имя пользователя в предыдущем вызове функции) с кодом внутри.

Пользователь читает код и предоставляет код к следующему вызову функции:

cognito.confirmSignUp({
    ClientId,
    ConfirmationCode: code,
    Username: email,
    ForceAliasCreation: false,
}).promise();
Первый вход в систему:
await cognito.adminInitiateAuth({
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    ClientId,
    UserPoolId,
    AuthParameters: {
        'USERNAME': email,
        'PASSWORD': password,
    },
}).promise();

На этом этапе возвращаемое значение будет другим (по сравнению с тем, что вы получите, если MFA не применяется). Возвращаемое значение будет примерно таким:

{
  "ChallengeName": "MFA_SETUP",
  "Session": "...",
  "ChallengeParameters": {
    "MFAS_CAN_SETUP": "[\"SOFTWARE_TOKEN_MFA\"]",
    "USER_ID_FOR_SRP": "..."
  }
}

Возвращенный объект говорит, что пользователь должен выполнить вызов MFA_SETUP, прежде чем он сможет войти в систему (это происходит один раз при регистрации пользователя).

Включите TOTP MFA для пользователя:
cognito.associateSoftwareToken({
  Session,
}).promise();

Предыдущий вызов необходим, потому что есть две опции, и, отправляя данный вызов, вы сообщаете Cognito, что вы хотите, чтобы ваш пользователь включить TOTP MFA (вместо SMS MFA). Вход Session - это результат, возвращаемый предыдущим вызовом функции. Теперь на этот раз он вернет это значение:

{
  "SecretCode": "...",
  "Session": "..."
}

Пользователь должен взять данное SecretCode и ввести его в приложение, такое как «Google Authenticator». После добавления приложение начнет показывать число 6 git, которое обновляется каждую минуту.

Проверьте приложение-аутентификатор:

cognito.verifySoftwareToken({
  UserCode: '123456',
  Session,
}).promise()

Вводом Session будет строка, возвращаемая на шаге 5, а UserCode - это 6 цифр, отображаемых в приложении для проверки подлинности в данный момент. Если это будет сделано успешно, вы получите это возвращаемое значение:

{
  "Status": "SUCCESS",
  "Session": "..."
}

Я не нашел никакого использования для сеанса, возвращаемого этим объектом. Теперь процесс регистрации завершен, и пользователь может войти в систему.

Фактический вход в систему (который происходит каждый раз, когда пользователи хотят аутентифицировать себя):
await cognito.adminInitiateAuth({
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    ClientId,
    UserPoolId,
    AuthParameters: {
        'USERNAME': email,
        'PASSWORD': password,
    },
}).promise();

Конечно, это было идентично шагу 4. Но его возвращаемое значение отличается:

{
  "ChallengeName": "SOFTWARE_TOKEN_MFA",
  "Session": "...",
  "ChallengeParameters": {
    "USER_ID_FOR_SRP": "..."
  }
}

Это говорит о том, что для завершения процесса входа в систему необходимо выполнить процесс вызова SOFTWARE_TOKEN_MFA.

Завершите процесс входа в систему, предоставив MFA:
cognito.adminRespondToAuthChallenge({
  ChallengeName: "SOFTWARE_TOKEN_MFA",
  ClientId,
  UserPoolId,
  ChallengeResponses: {
    "USERNAME": config.username,
    "SOFTWARE_TOKEN_MFA_CODE": mfa,
  },
  Session,
}).promise()

Вход Session - это тот, который возвращен на шаге 8, а mfa - это 6 цифр, которые необходимо прочитать из приложение для проверки подлинности. Как только вы вызовете функцию, она вернет токены:

{
  "ChallengeParameters": {},
  "AuthenticationResult": {
    "AccessToken": "...",
    "ExpiresIn": 3600,
    "TokenType": "Bearer",
    "RefreshToken": "...",
    "IdToken": "..."
  }
}
...