AWS Cognito用户迁移池触发器不适用于登录流程

时间:2020-06-13 04:24:56

标签: amazon-web-services aws-lambda amazon-cognito

我正在使用具有cognito执行角色的Lambda函数进行AWS cognito池迁移 以下是我的新泳池应用客户端设置

enter image description here

enter image description here AWS文档说

用户迁移身份验证流程用户迁移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}`);
            }
        }

并将触发器添加到新池中,

enter image description here

经过多次尝试,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}

2 个答案:

答案 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

相关问题