我正在使用具有cognito执行角色的Lambda函数进行AWS cognito池迁移 以下是我的新泳池应用客户端设置
或
用户迁移身份验证流程用户迁移Lambda触发器 允许从旧版用户管理系统轻松迁移用户 进入您的用户池。为避免让您的用户重设密码 在用户迁移期间,请选择USER_PASSWORD_AUTH身份验证 流。该流程将您的用户密码通过 身份验证期间加密的SSL连接。
完成所有用户的迁移后,我们建议 将流切换到更安全的SRP流。 SRP流程不 通过网络发送任何密码。
我创建了角色为“ AmazonCognitoPowerUser”的lambda函数
async function authenticateUser(cognitoISP: CognitoIdentityServiceProvider, username: string, password: string): Promise<User | undefined> {
console.log(`authenticateUser: user='${username}'`);
const params: AdminInitiateAuthRequest = {
AuthFlow: 'ADMIN_USER_PASSWORD_AUTH',
AuthParameters: {
PASSWORD: password,
USERNAME: username,
},
ClientId: OLD_CLIENT_ID,
UserPoolId: OLD_USER_POOL_ID,
};
const cognitoResponse = await cognitoISP.adminInitiateAuth(params).promise();
const awsError: AWSError = cognitoResponse as any as AWSError;
if (awsError.code && awsError.message) {
console.log(`authenticateUser: error ${JSON.stringify(awsError)}`);
return undefined;
}
console.log(`authenticateUser: found ${JSON.stringify(cognitoResponse)}`);
return lookupUser(cognitoISP, username);
}
async function lookupUser(cognitoISP: CognitoIdentityServiceProvider, username: string): Promise<User | undefined> {
console.log(`lookupUser: user='${username}'`);
const params = {
UserPoolId: OLD_USER_POOL_ID,
Username: username,
};
const cognitoResponse = await cognitoISP.adminGetUser(params).promise();
const awsError: AWSError = cognitoResponse as any as AWSError;
if (awsError.code && awsError.message) {
console.log(`lookupUser: error ${JSON.stringify(awsError)}`);
return undefined;
}
console.log(`lookupUser: found ${JSON.stringify(cognitoResponse)}`);
const userAttributes = cognitoResponse.UserAttributes ? cognitoResponse.UserAttributes.reduce((acc, entry) => ({
...acc,
[entry.Name]: entry.Value,
}), {} as {[key: string]: string | undefined}) : {};
const user: User = {
userAttributes,
userName: cognitoResponse.Username,
};
console.log(`lookupUser: response ${JSON.stringify(user)}`);
return user;
}
async function onUserMigrationAuthentication(cognitoISP: CognitoIdentityServiceProvider, event: CognitoUserPoolTriggerEvent) {
// authenticate the user with your existing user directory service
const user = await authenticateUser(cognitoISP, event.userName!, event.request.password!);
if (!user) {
throw new Error('Bad credentials');
}
event.response.userAttributes = {
// old_username: user.userName,
// 'custom:tenant': user.userAttributes['custom:tenant'],
email: user.userAttributes.email!,
email_verified: 'true',
preferred_username: user.userAttributes.preferred_username!,
};
event.response.finalUserStatus = 'CONFIRMED';
event.response.messageAction = 'SUPPRESS';
console.log(`Authentication - response: ${JSON.stringify(event.response)}`);
return event;
}
async function onUserMigrationForgotPassword(cognitoISP: CognitoIdentityServiceProvider, event: CognitoUserPoolTriggerEvent) {
// Lookup the user in your existing user directory service
const user = await lookupUser(cognitoISP, event.userName!);
if (!user) {
throw new Error('Bad credentials');
}
event.response.userAttributes = {
// old_username: user.userName,
// 'custom:tenant': user.userAttributes['custom:tenant'],
email: user.userAttributes.email!,
email_verified: 'true',
preferred_username: user.userAttributes.preferred_username!,
};
event.response.messageAction = 'SUPPRESS';
console.log(`Forgot password - response: ${JSON.stringify(event.response)}`);
return event;
}
export const handler = async (event: CognitoUserPoolTriggerEvent, context: Context): Promise<CognitoUserPoolTriggerEvent> => {
const options: CognitoIdentityServiceProvider.Types.ClientConfiguration = {
region: OLD_USER_POOL_REGION,
};
if (OLD_ROLE_ARN) {
options.credentials = new ChainableTemporaryCredentials({
params: {
ExternalId: OLD_EXTERNAL_ID,
RoleArn: OLD_ROLE_ARN,
RoleSessionName: context.awsRequestId,
},
});
}
const cognitoIdentityServiceProvider = new CognitoIdentityServiceProvider(options);
switch (event.triggerSource) {
case 'UserMigration_Authentication':
return onUserMigrationAuthentication(cognitoIdentityServiceProvider, event);
case 'UserMigration_ForgotPassword':
return onUserMigrationForgotPassword(cognitoIdentityServiceProvider, event);
default:
throw new Error(`Bad triggerSource ${event.triggerSource}`);
}
}
并将触发器添加到新池中,
经过多次尝试,Lambda触发器无法用于登录,始终会出错。
{__type: "NotAuthorizedException", message: "Incorrect username or password."}
message: "Incorrect username or password."
__type: "NotAuthorizedException"
尽管如果我们使用“忘记密码”流程,但在重置密码用户迁移到新池后仍能正常工作
已更新:
使用以下json直接在lambda上运行测试时
{
"version": "1",
"triggerSource": "UserMigration_Authentication",
"region": "ap-south-1",
"userPoolId": "ap-XXXXXXXXX2",
"userName": "vaquar.test@gmail.com",
"callerContext": {
"awsSdkVersion": "aws-sdk-unknown-unknown",
"clientId": "1XXXXXXXXXXXXXXXXXXfgk"
},
"request": {
"password": "vkhan",
"validationData": null,
"userAttributes": null
},
"response": {
"userAttributes": null,
"forceAliasCreation": null,
"finalUserStatus": null,
"messageAction": null,
"desiredDeliveryMediums": null
}
}
然后得到以下响应,并且用户迁移到新池中,这意味着我们在登录期间触发了问题。
INFO Authentication - response: {"userAttributes":{"email":"vaquar.test@gmail.com","email_verified":"true"},"forceAliasCreation":null,"finalUserStatus":"CONFIRMED","messageAction":"SUPPRESS","desiredDeliveryMediums":null}
答案 0 :(得分:0)
使用Lambda触发器,Cognito服务将调用Lambda函数。因此Cognito将需要permission to invoke Lambda function。您如何在用户池上配置Lambda触发器?如果您使用的是AWS Cognito控制台,则应自动设置权限。
您也可能verify if the user already exists in the new userpool会导致这种行为。
答案 1 :(得分:0)
请确认您的应用程序使用的是 OAUTH 流 USER_PASSWORD 而不是默认的 USER_SRP_AUTH。
供参考:link