Я хочу реализовать решение для аутентификации без пароля в соответствии с https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/
У меня есть основы этой работы, но мои проблемы возникают, когда я добавляю отслеживание устройств.У меня есть возможность вызывать verifyDevice для успешного подтверждения и запоминания устройства.
Проблема № 1 - последующий вызов initiateAuth, включая DEVICE_KEY в качестве параметра auth, похоже, ничего не делает.Мне по-прежнему предоставляется newDeviceMetadata при успешной аутентификации, указывающее, что он, похоже, не распознает, что я вхожу в систему с запомненного устройства.
Проблема # 2 - хотя я могу использовать refreshToken для получения действительных токенов, я нахожуэто должно быть несколько небезопасно, как если бы кто-то смог получить refreshToken, он мог получить к нему доступ из любого места.Я хотел бы иметь возможность реализовать DEVICE_SRP_AUTH и DEVICE_PASSWORD_VERIFIER, чтобы пользователю приходилось входить в систему только один раз с помощью текстового кода / кода электронной почты, а затем устройство могло бы при необходимости повторно пройти аутентификацию, используя пароль, сгенерированный для этого устройства.
Я смог реализовать это как 2-й клиент приложения (единственный способ выяснить, как сказать, что мне нужен другой поток), и я могу пройти весь процесс до вызова DEVICE_PASSWORD_VERIFIER.Однако я не могу обойти ошибку:
com.amazonaws.services.cognitoidp.model.NotAuthorizedException: неверное имя пользователя или пароль.(Сервис: AWSCognitoIdentityProvider; Код состояния: 400; Код ошибки: NotAuthorizedException; Идентификатор запроса: fa48d3ce-6b90-11e9-a13a-0507dac88eff)
Мое решение состоит из множества частей, у меня есть Java-оболочка для сервиса cognito sdkи затем, хотя в конечном итоге это будет сделано для мобильного приложения, в качестве тестового набора у меня есть веб-клиент на основе JavaScript.Чтобы (надеюсь) уменьшить вероятность ошибки в процессе SRP, я использую библиотеку amazon-cognito-identity-js (версия 3.0.11) для вычислений SRP, достаточно близко отражая код в CognitoUser.js
Мой поток: 1. Пользователь зарегистрирован и подтвержден 2. Пользователь входит в систему, введя адрес электронной почты или номер телефона - получает код подтверждения и вводит код подтверждения в качестве ответа на запрос.3. Токены получены и подтверждают, что устройство называется
фрагмент кода жгута для вызова verifyDevice (доступ к sdk обернут в оболочку java, но это в значительной степени пропуск)
let challengeResponse = prompt("please enter the code");
fetch('http://localhost:9887/api/v1/users/verifyCode?code=' + challengeResponse, {
headers: {
"Accept": "application/json",
username: json.username,
session: json.session,
deviceName: navigator.userAgent
}
}).then(response => response.json())
.then(challengeJson => {
console.log(challengeJson);
authenticationHelper.generateHashDevice(
challengeJson.deviceGroupKey,
challengeJson.deviceKey,
(errGenHash) => {
if (errGenHash) {
console.log(errGenHash)
}
});
let salt = Buffer.from(authenticationHelper.getSaltDevices(), 'hex').toString('base64');
let passwordVerifier = Buffer.from(authenticationHelper.getVerifierDevices(), 'hex').toString('base64');
//need to store this off so it can be used later
let randomPassword = authenticationHelper.getRandomPassword();
localStorage.setItem("randomPassword", randomPassword);
localStorage.setItem("deviceGroupKey", challengeJson.deviceGroupKey);
localStorage.setItem("deviceKey", challengeJson.deviceKey);
fetch('http://localhost:9887/api/v1/users/confirmDevice', {
headers: {
"Accept": "application/json",
accessToken: challengeJson.accessToken,
deviceKey: challengeJson.deviceKey,
deviceName: navigator.userAgent,
passwordVerifier: passwordVerifier,
salt: salt
}
});
}).catch(function (challengeError) {
console.log(challengeError);
});
Теперь пользователь прошел проверку подлинности и устройство подтверждено, пароль, devicekey и deviceGroupKey все хранятся в локальном хранилище.
Теперь я хочу снова вызвать initgin auth, но вместо того, чтобы отвечать на вызов, я хочу использоватьпароль устройства для аутентификации.
if (json.challengeName === 'DEVICE_SRP_AUTH') {
let deviceGroupKey = localStorage.getItem("deviceGroupKey");
let randomPassword = localStorage.getItem("randomPassword");
let session = json.session;
authenticationHelper.getLargeAValue((errAValue, aValue) => {
fetch('http://localhost:9887/api/v1/users/signindevice', {
headers: {
"Accept": "application/json",
username: json.username,
session: session,
"deviceKey": deviceKey,
"srpA": aValue.toString(16)
}
}).then(response => response.json())
.then(json => {
const serverBValue = new BigInteger(json.srpB, 16);
const salt = new BigInteger(json.salt, 16);
authenticationHelper.getPasswordAuthenticationKey(
deviceKey,
randomPassword,
serverBValue,
salt,
(errHkdf, hkdf) => {
// getPasswordAuthenticationKey callback start
if (errHkdf) {
return callback.onFailure(errHkdf);
}
const dateHelper = new DateHelper();
const dateNow = dateHelper.getNowString();
const message = CryptoJS.lib.WordArray.create(
Buffer.concat([
Buffer.from(deviceGroupKey, 'utf8'),
Buffer.from(deviceKey, 'utf8'),
Buffer.from(json.secretBlock, 'base64'),
Buffer.from(dateNow, 'utf8'),
])
);
const key = CryptoJS.lib.WordArray.create(hkdf);
const signatureString = Base64.stringify(HmacSHA256(message, key));
fetch('http://localhost:9887/api/v1/users/signindeviceresponse', {
headers: {
"Accept": "application/json",
username: json.username,
session: session,
"deviceKey": deviceKey,
"secretBlock": json.secretBlock,
"signature": signatureString,
"timestamp": dateNow
}
}).then(response => response.json())
.then(json => {
console.log(json);
});
});
});
});
}
И вот где я получаю ошибку 400.
Я попытался включить / отключить различные параметры в моем пуле пользователей, но пока нетпройти эту ошибку
Я не могу найти много документации по этому устройству, так что то, что я пытаюсь сделать, даже поддерживается?В документах говорится, что этот вызов возвращается только после других испытаний, поэтому стоит ли начинать с SRP?
Любая помощь очень ценится.