AWSTemplateFormatVersion: 2010-09-09

Parameters:
  env:
    Type: String
  authRoleArn:
    Type: String
  unauthRoleArn:
    Type: String
  
  

    
  identityPoolName:
    Type: String
                
  allowUnauthenticatedIdentities:
    Type: String
            
  resourceNameTruncated:
    Type: String
              
  userPoolName:
    Type: String
                      
  autoVerifiedAttributes:
    Type: CommaDelimitedList
      
  mfaConfiguration:
    Type: String
                      
  mfaTypes:
    Type: CommaDelimitedList
      
  smsAuthenticationMessage:
    Type: String
              
  smsVerificationMessage:
    Type: String
              
  emailVerificationSubject:
    Type: String
              
  emailVerificationMessage:
    Type: String
                
  defaultPasswordPolicy:
    Type: String
                
  passwordPolicyMinLength:
    Type: Number
                  
  passwordPolicyCharacters:
    Type: CommaDelimitedList
              
  requiredAttributes:
    Type: CommaDelimitedList
        
  userpoolClientGenerateSecret:
    Type: String
                
  userpoolClientRefreshTokenValidity:
    Type: Number
                  
  userpoolClientWriteAttributes:
    Type: CommaDelimitedList
              
  userpoolClientReadAttributes:
    Type: CommaDelimitedList
      
  userpoolClientLambdaRole:
    Type: String
                
  userpoolClientSetAttributes:
    Type: String
            
  resourceName:
    Type: String
              
  authSelections:
    Type: String
                                      
  useDefault:
    Type: String
                      
  userPoolGroupList:
    Type: CommaDelimitedList
                          
  dependsOn:
    Type: CommaDelimitedList
    
Conditions:
  ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ]

Resources:
  
  
  # BEGIN SNS ROLE RESOURCE
  SNSRole: 
  # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process
    Type: AWS::IAM::Role
    Properties:
      RoleName: !If [ShouldNotCreateEnvResources, 'photosb143529b_sns-role', !Join ['',[ 'sns', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]]
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Sid: ""
            Effect: "Allow"
            Principal: 
              Service: "cognito-idp.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
            Condition: 
              StringEquals:
                sts:ExternalId: photosb143529b_role_external_id
      Policies: 
        - 
          PolicyName: photosb143529b-sns-policy
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - 
                Effect: "Allow"
                Action: 
                  - "sns:Publish"
                Resource: "*"
  # BEGIN USER POOL RESOURCES
  UserPool:
  # Created upon user selection
  # Depends on SNS Role for Arn if MFA is enabled
    Type: AWS::Cognito::UserPool
    UpdateReplacePolicy: Retain
    Properties:
      UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]]
      
      Schema: 
        
        -
          Name: email
          Required: true
          Mutable: true
        
      
      
      
      AutoVerifiedAttributes: !Ref autoVerifiedAttributes
      
      
      EmailVerificationMessage: !Ref emailVerificationMessage
      EmailVerificationSubject: !Ref emailVerificationSubject
            
      Policies:
        PasswordPolicy:
          MinimumLength: !Ref passwordPolicyMinLength
          RequireLowercase: false
          RequireNumbers: false
          RequireSymbols: false
          RequireUppercase: false
          
      MfaConfiguration: !Ref mfaConfiguration
      SmsVerificationMessage: !Ref smsVerificationMessage
      SmsConfiguration: 
        SnsCallerArn: !GetAtt SNSRole.Arn
        ExternalId: photosb143529b_role_external_id
    
  
  UserPoolClientWeb:
  # Created provide application access to user pool
  # Depends on UserPool for ID reference
    Type: "AWS::Cognito::UserPoolClient"
    Properties:
      ClientName: photosb143529b_app_clientWeb
      
      RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
      UserPoolId: !Ref UserPool
    DependsOn: UserPool
  UserPoolClient:
  # Created provide application access to user pool
  # Depends on UserPool for ID reference
    Type: "AWS::Cognito::UserPoolClient"
    Properties:
      ClientName: photosb143529b_app_client
      
      GenerateSecret: !Ref userpoolClientGenerateSecret
      RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
      UserPoolId: !Ref UserPool
    DependsOn: UserPool
  # BEGIN USER POOL LAMBDA RESOURCES
  UserPoolClientRole:
  # Created to execute Lambda which gets userpool app client config values
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]]
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
    DependsOn: UserPoolClient
  UserPoolClientLambda:
  # Lambda which gets userpool app client config values
  # Depends on UserPool for id
  # Depends on UserPoolClientRole for role ARN
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile: !Join 
          - |+
          - - 'const response = require(''cfn-response'');'
            - 'const aws = require(''aws-sdk'');'
            - 'const identity = new aws.CognitoIdentityServiceProvider();'
            - 'exports.handler = (event, context, callback) => {'
            - ' if (event.RequestType == ''Delete'') { '
            - '   response.send(event, context, response.SUCCESS, {})'
            - ' }'
            - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
            - '   const params = {'
            - '     ClientId: event.ResourceProperties.clientId,'
            - '     UserPoolId: event.ResourceProperties.userpoolId'
            - '   };'
            - '   identity.describeUserPoolClient(params).promise()'
            - '     .then((res) => {'
            - '       response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});'   
            - '     })'
            - '     .catch((err) => {'
            - '       response.send(event, context, response.FAILED, {err});'
            - '     });'
            - ' }'
            - '};'
      Handler: index.handler
      Runtime: nodejs12.x
      Timeout: '300'
      Role: !GetAtt 
        - UserPoolClientRole
        - Arn
    DependsOn: UserPoolClientRole
  UserPoolClientLambdaPolicy:
  # Sets userpool policy for the role that executes the Userpool Client Lambda
  # Depends on UserPool for Arn
  # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: photosb143529b_userpoolclient_lambda_iam_policy
      Roles: 
        - !Ref UserPoolClientRole
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
              - 'cognito-idp:DescribeUserPoolClient'
            Resource: !GetAtt UserPool.Arn
    DependsOn: UserPoolClientLambda
  UserPoolClientLogPolicy:
  # Sets log policy for the role that executes the Userpool Client Lambda
  # Depends on UserPool for Arn
  # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: photosb143529b_userpoolclient_lambda_log_policy
      Roles: 
        - !Ref UserPoolClientRole
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - 'logs:CreateLogGroup'
              - 'logs:CreateLogStream'
              - 'logs:PutLogEvents'
            Resource: !Sub  
              - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
              - { region: !Ref "AWS::Region",  account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda}
    DependsOn: UserPoolClientLambdaPolicy  
  UserPoolClientInputs:
  # Values passed to Userpool client Lambda
  # Depends on UserPool for Id
  # Depends on UserPoolClient for Id
  # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
    Type: 'Custom::LambdaCallout'
    Properties:
      ServiceToken: !GetAtt UserPoolClientLambda.Arn
      clientId: !Ref UserPoolClient
      userpoolId: !Ref UserPool
    DependsOn: UserPoolClientLogPolicy
  

  
  

  
    
  # BEGIN IDENTITY POOL RESOURCES
  
 
  IdentityPool:
  # Always created
    Type: AWS::Cognito::IdentityPool
    Properties: 
      IdentityPoolName: !If [ShouldNotCreateEnvResources, 'photoshareb143529b_identitypool_b143529b', !Join ['',['photoshareb143529b_identitypool_b143529b', '__', !Ref env]]]
      
      CognitoIdentityProviders:
        - ClientId:  !Ref UserPoolClient
          ProviderName: !Sub
            - cognito-idp.${region}.amazonaws.com/${client}
            - { region: !Ref "AWS::Region",  client: !Ref UserPool}
        - ClientId:  !Ref UserPoolClientWeb
          ProviderName: !Sub
            - cognito-idp.${region}.amazonaws.com/${client}
            - { region: !Ref "AWS::Region",  client: !Ref UserPool}
            
      AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities
       
       
    DependsOn: UserPoolClientInputs 
    
  
  IdentityPoolRoleMap:
  # Created to map Auth and Unauth roles to the identity pool
  # Depends on Identity Pool for ID ref
    Type: AWS::Cognito::IdentityPoolRoleAttachment
    Properties: 
      IdentityPoolId: !Ref IdentityPool
      Roles:
          unauthenticated: !Ref unauthRoleArn
          authenticated: !Ref authRoleArn
    DependsOn: IdentityPool
  

Outputs :
  
  IdentityPoolId:
    Value: !Ref 'IdentityPool'
    Description:  Id for the identity pool
  IdentityPoolName:
    Value: !GetAtt IdentityPool.Name 
  
  
  
  
  UserPoolId:
    Value: !Ref 'UserPool'
    Description:  Id for the user pool
  UserPoolName:
    Value: !Ref userPoolName
  AppClientIDWeb:
    Value: !Ref 'UserPoolClientWeb'
    Description: The user pool app client id for web
  AppClientID:
    Value: !Ref 'UserPoolClient'
    Description: The user pool app client id
  AppClientSecret:
    Value: !GetAtt UserPoolClientInputs.appSecret