async saveCognitoUserPool()

in addons/addon-base-rest-api/packages/services/lib/authentication-providers/built-in-providers/cogito-user-pool/provisioner-service.js [134:247]


  async saveCognitoUserPool(providerConfig) {
    this.log.info('Creating or configuring Cognito User Pool');

    const aws = await this.service('aws');
    const cognitoIdentityServiceProvider = new aws.sdk.CognitoIdentityServiceProvider();

    const envType = this.settings.get(settingKeys.envType);
    const envName = this.settings.get(settingKeys.envName);
    const solutionName = this.settings.get(settingKeys.solutionName);
    const userPoolName = providerConfig.userPoolName || `${envName}-${envType}-${solutionName}-userpool`;

    // Get PreSignUpLambdaArn output from CFN stack, get undefined if not present
    const preSignUpLambdaArn = await this.getPreSignUpLambdaArn();

    const params = {
      AdminCreateUserConfig: {
        AllowAdminCreateUserOnly: !this.settings.getBoolean(settingKeys.enableUserSignUps),
      },
      LambdaConfig:
        this.settings.getBoolean(settingKeys.enableNativeUserPoolUsers) &&
        this.settings.getBoolean(settingKeys.autoConfirmNativeUsers)
          ? {
              PreSignUp: preSignUpLambdaArn,
            }
          : undefined,
      AutoVerifiedAttributes: ['email'],
      Schema: [
        {
          Name: 'name',
          Mutable: true,
          Required: true,
        },
        {
          Name: 'family_name',
          Mutable: true,
          Required: true,
        },
        {
          Name: 'middle_name',
          Mutable: true,
          Required: false,
        },
      ],
    };

    let userPoolArn;
    if (providerConfig.userPoolId) {
      // If userPoolId is specified then this must be for update so make sure it points to a valid cognito user pool
      try {
        const poolDetails = await cognitoIdentityServiceProvider
          .describeUserPool({ UserPoolId: providerConfig.userPoolId })
          .promise();
        userPoolArn = poolDetails.UserPool.Arn;

        this.log.info('Updating Cognito User Pool as per config changes, if any');
        const updateParams = {
          UserPoolId: providerConfig.userPoolId,
          AdminCreateUserConfig: {
            AllowAdminCreateUserOnly: !this.settings.getBoolean(settingKeys.enableUserSignUps),
          },
          LambdaConfig: {
            // We don't check for autoConfirmNativeUsers and enableNativeUserPoolUsers config setting values in the update cycle
            // because preSignUp lambda is created based on the same conditions, therefore this logic can set or reset the cognito trigger
            PreSignUp: preSignUpLambdaArn,
          },
        };
        await cognitoIdentityServiceProvider.updateUserPool(updateParams).promise();
      } catch (err) {
        if (err.code === 'ResourceNotFoundException') {
          throw this.boom.badRequest(
            'Can not update Cognito User Pool. No Cognito User Pool with the given userPoolId exists.',
            true,
          );
        }
        // In case of any other error, let it propagate
        throw err;
      }
    } else {
      // userPoolId is not specified so create new user pool
      params.PoolName = userPoolName;
      const data = await cognitoIdentityServiceProvider.createUserPool(params).promise();
      userPoolArn = data.UserPool.Arn;
      providerConfig.userPoolId = data.UserPool.Id;
    }

    // If PreSignUpLambdaArn is not undefined, allow it to be invoked by Cognito
    if (!_.isUndefined(preSignUpLambdaArn)) {
      const lambda = new aws.sdk.Lambda();
      const invokePermParam = {
        Action: 'lambda:InvokeFunction',
        FunctionName: preSignUpLambdaArn,
        Principal: 'cognito-idp.amazonaws.com',
        StatementId: 'CognitoLambdaInvokePermission',
        SourceArn: userPoolArn,
      };

      try {
        await lambda.addPermission(invokePermParam).promise();
      } catch (err) {
        if (err.code === 'ResourceConflictException') {
          this.log.info('Lambda invoke permission already assigned');
        } else {
          // In case of any other error, let it propagate
          throw this.boom.badRequest(
            `Adding cognito invoke permission to lambda ${preSignUpLambdaArn} failed with code: ${err.code}`,
            true,
          );
        }
      }
    }

    providerConfig.userPoolName = userPoolName;
    return providerConfig;
  }