# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  Template to deploy lambda functions as part of bootstrap
Parameters:
  CognitoOperationUsersUserPoolId:
    Type: String
  CognitoOperationUsersUserPoolClientId:
    Type: String
  CognitoUserPoolId: 
    Type: String
  CognitoUserPoolClientId: 
    Type: String  
  TenantDetailsTableArn:
    Type: String
  TenantUserMappingTableArn:
    Type: String  
Globals:
  Function:
    Timeout: 29
    Layers:
      - !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:14"
    Environment:
      Variables:
        LOG_LEVEL: DEBUG        
        POWERTOOLS_METRICS_NAMESPACE: "ServerlessSaaS"
        
Resources:
  ServerlessSaaSLayers:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: serverless-saas-dependencies
      Description: Utilities for project
      ContentUri: ../layers/
      CompatibleRuntimes:
        - python3.9
      LicenseInfo: "MIT"
      RetentionPolicy: Retain
    Metadata:
      BuildMethod: python3.9

  
  AuthorizerExecutionRole:
    Type: AWS::IAM::Role     
    Properties:
      RoleName: authorizer-execution-role
      Path: '/'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy    
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess   
      Policies:      
        - PolicyName: authorizer-execution-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - cognito-idp:List*                                    
                Resource:
                  - !Sub arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/*    
              - Effect: Allow
                Action:
                  - dynamodb:GetItem
                Resource:
                  - !Ref TenantDetailsTableArn    
  
  SharedServicesAuthorizerFunction:
    Type: AWS::Serverless::Function 
    DependsOn: AuthorizerExecutionRole
    Properties:
      CodeUri: ../Resources/
      Handler: shared_service_authorizer.lambda_handler
      Runtime: python3.9
      Role: !GetAtt AuthorizerExecutionRole.Arn
      MemorySize: 256
      Tracing: Active
      Layers: 
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          OPERATION_USERS_USER_POOL: !Ref CognitoOperationUsersUserPoolId
          OPERATION_USERS_APP_CLIENT: !Ref CognitoOperationUsersUserPoolClientId          
          
  #Create user pool for the tenant
  TenantUserPoolLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub tenant-userpool-lambda-execution-role-${AWS::Region}
      Path: "/"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy    
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
      Policies:
        - PolicyName: !Sub tenant-userpool-lambda-execution-policy-${AWS::Region}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - cognito-idp:*
                Resource: "*"
              - Effect: Allow
                Action:
                  - dynamodb:GetItem
                Resource:
                  - !Ref TenantDetailsTableArn
              - Effect: Allow
                Action:
                  - dynamodb:GetItem
                  - dynamodb:Query
                Resource:
                  - !Ref TenantUserMappingTableArn
  CreateUserLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub create-user-lambda-execution-role-${AWS::Region}
      Path: "/"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole          
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy    
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
      Policies:
        - PolicyName: !Sub create-user-lambda-execution-policy-${AWS::Region}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - cognito-idp:*
                Resource: "*"
              - Effect: Allow
                Action:
                  - dynamodb:PutItem
                Resource:
                  - !Ref TenantUserMappingTableArn
              - Effect: Allow
                Action:
                  - dynamodb:GetItem
                Resource:
                  - !Ref TenantDetailsTableArn
  CreateTenantAdminUserFunction:
    Type: AWS::Serverless::Function
    DependsOn: CreateUserLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.create_tenant_admin_user
      Runtime: python3.9
      Role: !GetAtt CreateUserLambdaExecutionRole.Arn      
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          TENANT_APP_CLIENT_ID: !Ref CognitoUserPoolClientId
          POWERTOOLS_SERVICE_NAME: "UserManagement.CreateTenantAdmin"
      
  #User management
  CreateUserFunction:
    Type: AWS::Serverless::Function
    DependsOn: CreateUserLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.create_user
      Runtime: python3.9
      Role: !GetAtt CreateUserLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers      
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.CreateUser"   
      

  UpdateUserFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantUserPoolLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.update_user
      Runtime: python3.9
      Role: !GetAtt TenantUserPoolLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.UpdateUser"
      
  DisableUserFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantUserPoolLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.disable_user
      Runtime: python3.9
      Role: !GetAtt TenantUserPoolLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers      
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.DisableUser"
      
  DisableUsersByTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantUserPoolLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.disable_users_by_tenant
      Runtime: python3.9
      Role: !GetAtt TenantUserPoolLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers      
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.DisableUsersByTenant"
           
  EnableUsersByTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantUserPoolLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.enable_users_by_tenant
      Runtime: python3.9
      Role: !GetAtt TenantUserPoolLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers      
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.EnableUsersByTenant"
      
  GetUserFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantUserPoolLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.get_user
      Runtime: python3.9
      Role: !GetAtt TenantUserPoolLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers      
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.GetUser"
         
  GetUsersFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantUserPoolLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: user-management.get_users
      Runtime: python3.9
      Role: !GetAtt TenantUserPoolLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers      
      Environment:
        Variables:
          TENANT_USER_POOL_ID: !Ref CognitoUserPoolId
          POWERTOOLS_SERVICE_NAME: "UserManagement.GetUsers"  
      
  #Tenant Management
  TenantManagementLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub tenant-management-lambda-execution-role-${AWS::Region}
      Path: "/"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy    
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
      Policies:
        - PolicyName: !Sub create-tenant-execution-policy-${AWS::Region}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - dynamodb:PutItem
                  - dynamodb:GetItem
                  - dynamodb:UpdateItem
                  - dynamodb:Scan
                  - dynamodb:Query
                Resource:
                  - !Ref TenantDetailsTableArn  
                  - !Join ["", [!Ref TenantDetailsTableArn, '/index/*']]               
  CreateTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantManagementLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-management.create_tenant
      Runtime: python3.9
      Role: !GetAtt TenantManagementLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: "TenantManagement.CreateTenant"
      
  ActivateTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantManagementLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-management.activate_tenant
      Runtime: python3.9
      Role: !GetAtt TenantManagementLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: "TenantManagement.ActivateTenant"
          ENABLE_USERS_BY_TENANT: "/users/enable"
          PROVISION_TENANT: "/provisioning/"
  
  GetTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantManagementLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-management.get_tenant
      Runtime: python3.9
      Role: !GetAtt TenantManagementLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: "TenantManagement.GetTenant"    
        
  DeactivateTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantManagementLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-management.deactivate_tenant
      Runtime: python3.9
      Role: !GetAtt TenantManagementLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: "TenantManagement.DeactivateTenant"
          DEPROVISION_TENANT: "/provisioning/"
          DISABLE_USERS_BY_TENANT: "/users/disable"
  UpdateTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantManagementLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-management.update_tenant
      Runtime: python3.9
      Role: !GetAtt TenantManagementLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: "TenantManagement.UpdateTenant"          
  GetTenantsFunction:
    Type: AWS::Serverless::Function
    DependsOn: TenantManagementLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-management.get_tenants
      Runtime: python3.9
      Role: !GetAtt TenantManagementLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers 
  
  #Tenant Registration
  RegisterTenantLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub tenant-registration-lambda-execution-role-${AWS::Region}
      Path: "/"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy    
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess      
  RegisterTenantFunction:
    Type: AWS::Serverless::Function
    DependsOn: RegisterTenantLambdaExecutionRole
    Properties:
      CodeUri: ../TenantManagementService/
      Handler: tenant-registration.register_tenant
      Runtime: python3.9
      Role: !GetAtt RegisterTenantLambdaExecutionRole.Arn
      Tracing: Active
      Layers:
        - !Ref ServerlessSaaSLayers
      Environment:
        Variables: # Need to find a better way than hard coding resource paths
          CREATE_TENANT_ADMIN_USER_RESOURCE_PATH: "/user/tenant-admin"
          CREATE_TENANT_RESOURCE_PATH: "/tenant"
          PROVISION_TENANT_RESOURCE_PATH: "/provisioning"
          POWERTOOLS_SERVICE_NAME: "TenantRegistration.RegisterTenant"  
  
   
  
Outputs:
  RegisterTenantLambdaExecutionRoleArn: 
    Value: !GetAtt RegisterTenantLambdaExecutionRole.Arn          
  TenantManagementLambdaExecutionRoleArn: 
    Value: !GetAtt TenantManagementLambdaExecutionRole.Arn          
  RegisterTenantFunctionArn: 
    Value: !GetAtt RegisterTenantFunction.Arn
  ActivateTenantFunctionArn: 
    Value: !GetAtt ActivateTenantFunction.Arn
  GetTenantsFunctionArn: 
    Value: !GetAtt GetTenantsFunction.Arn
  CreateTenantFunctionArn: 
    Value: !GetAtt CreateTenantFunction.Arn
  GetTenantFunctionArn: 
    Value: !GetAtt GetTenantFunction.Arn          
  DeactivateTenantFunctionArn: 
    Value: !GetAtt DeactivateTenantFunction.Arn          
  UpdateTenantFunctionArn: 
    Value: !GetAtt UpdateTenantFunction.Arn
  GetUsersFunctionArn:
    Value: !GetAtt GetUsersFunction.Arn            
  GetUserFunctionArn: 
    Value: !GetAtt GetUserFunction.Arn          
  UpdateUserFunctionArn: 
    Value: !GetAtt UpdateUserFunction.Arn          
  DisableUserFunctionArn: 
    Value: !GetAtt DisableUserFunction.Arn
  CreateTenantAdminUserFunctionArn: 
    Value: !GetAtt CreateTenantAdminUserFunction.Arn
  CreateUserFunctionArn: 
    Value: !GetAtt CreateUserFunction.Arn
  DisableUsersByTenantFunctionArn: 
    Value: !GetAtt DisableUsersByTenantFunction.Arn
  EnableUsersByTenantFunctionArn: 
    Value: !GetAtt EnableUsersByTenantFunction.Arn          
  SharedServicesAuthorizerFunctionArn: 
    Value: !GetAtt SharedServicesAuthorizerFunction.Arn