AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: User management

Parameters:
  IdentityPoolPrefix:
    Type: String
    Description: The prefix used in naming the IdentityPool

  ProjectPrefix:
    Type: String
    Description: Project prefix used to name the Cognito user pool

  StageName:
    Type: String
    Description: Application stage name

Resources:
  PreSignupLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.singUpAutoConfirm
      Runtime: nodejs8.10
      InlineCode: |
        exports.singUpAutoConfirm = async (event, context, callback) => {
          event.response.autoConfirmUser = true
          return event }

  LambdaCognitoUserPoolExecutionPermission:
    Type: AWS::Lambda::Permission
    Properties: 
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt PreSignupLambdaFunction.Arn
      Principal: cognito-idp.amazonaws.com
      SourceArn: !Sub 'arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${UserPool}'

  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: !Sub ${ProjectPrefix}-${StageName}-userpool
      AutoVerifiedAttributes:
        - email
      UsernameAttributes:
        - email
      Schema:
        - Name: email
          AttributeDataType: String
          Required: true
          Mutable: false
        - Name: name
          AttributeDataType: String
          Required: true
          Mutable: true
        - Name: family_name
          AttributeDataType: String
          Required: true
          Mutable: true
        - Name: city
          AttributeDataType: String
          Mutable: true
        - Name: country
          AttributeDataType: String
          Mutable: true
      LambdaConfig:
        PreSignUp: !GetAtt PreSignupLambdaFunction.Arn

  UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      ClientName: !Sub ${ProjectPrefix}-client
      UserPoolId: !Ref UserPool
      GenerateSecret: false

  IdentityPool:
    Type: AWS::Cognito::IdentityPool
    Properties:
      IdentityPoolName: !Sub ${IdentityPoolPrefix}_${StageName}_Identity
      AllowUnauthenticatedIdentities: false
      CognitoIdentityProviders:
        - ClientId: !Ref UserPoolClient
          ProviderName: !GetAtt UserPool.ProviderName

  CognitoUnAuthorizedRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              Federated: 'cognito-identity.amazonaws.com'
            Action:
              - 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPool
              'ForAnyValue:StringLike':
                'cognito-identity.amazonaws.com:amr': unauthenticated
      Policies:
        - PolicyName: 'CognitoUnauthorizedPolicy'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action:
                  - 'mobileanalytics:PutEvents'
                  - 'cognito-sync:*'
                Resource: '*'

  CognitoAuthorizedRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              Federated: 'cognito-identity.amazonaws.com'
            Action:
              - 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPool
              'ForAnyValue:StringLike':
                'cognito-identity.amazonaws.com:amr': authenticated
      Policies:
        - PolicyName: 'CognitoAuthorizedPolicy'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action:
                  - 'mobileanalytics:PutEvents'
                  - 'cognito-sync:*'
                  - 'cognito-identity:*'
                Resource: '*'
              - Effect: 'Allow'
                Action:
                  - 'lambda:InvokeFunction'
                Resource: '*'
              - Effect: 'Allow'
                Action:
                  - 'execute-api:Invoke'
                Resource: '*'

  IdentityPoolRoleMapping:
    Type: 'AWS::Cognito::IdentityPoolRoleAttachment'
    Properties:
      IdentityPoolId: !Ref IdentityPool
      Roles:
        authenticated: !GetAtt CognitoAuthorizedRole.Arn
        unauthenticated: !GetAtt CognitoUnAuthorizedRole.Arn

Outputs:
  UserPoolId:
    Value: !Ref UserPool
    Export:
      Name: !Sub ${ProjectPrefix}-${StageName}-UserPool::Id
  UserPoolArn:
    Value: !GetAtt UserPool.Arn
    Export:
      Name: !Sub ${ProjectPrefix}-${StageName}-UserPool::Arn
  UserPoolClientId:
    Value: !Ref UserPoolClient
    Export:
      Name: !Sub ${ProjectPrefix}-${StageName}-UserPoolClient::Id
  IdentityPoolId:
    Value: !Ref IdentityPool
    Export:
      Name: !Sub ${ProjectPrefix}-${StageName}-IdentityPool::Id