def lambda_handler()

in Lab6/server/Resources/tenant_authorizer.py [0:0]


def lambda_handler(event, context):
    
    #get JWT token after Bearer from authorization
    token = event['authorizationToken'].split(" ")
    if (token[0] != 'Bearer'):
        raise Exception('Authorization header should have a format Bearer <JWT> Token')
    jwt_bearer_token = token[1]
    logger.info("Method ARN: " + event['methodArn'])
    
    #only to get tenant id to get user pool info
    unauthorized_claims = jwt.get_unverified_claims(jwt_bearer_token)
    logger.info(unauthorized_claims)

    if(auth_manager.isSaaSProvider(unauthorized_claims['custom:userRole'])):
        userpool_id = user_pool_operation_user
        appclient_id = app_client_operation_user   
        api_key = api_key_operation_user  
    else:
        #get tenant user pool and app client to validate jwt token against
        tenant_details = table_tenant_details.get_item( 
            Key ={
                'tenantId': unauthorized_claims['custom:tenantId']
            }
        )
        logger.info(tenant_details)
        userpool_id = tenant_details['Item']['userPoolId']
        appclient_id = tenant_details['Item']['appClientId']
        apigateway_url = tenant_details['Item']['apiGatewayUrl']
        #TODO: Get API Key from tenant management table
        #api_key = tenant_details['Item']['apiKey']
        

    #get keys for tenant user pool to validate
    keys_url = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format(region, userpool_id)
    with urllib.request.urlopen(keys_url) as f:
        response = f.read()
    keys = json.loads(response.decode('utf-8'))['keys']

    #authenticate against cognito user pool using the key
    response = validateJWT(jwt_bearer_token, appclient_id, keys)
    
    #get authenticated claims
    if (response == False):
        logger.error('Unauthorized')
        raise Exception('Unauthorized')
    else:
        logger.info(response)
        principal_id = response["sub"]
        user_name = response["cognito:username"]
        tenant_id = response["custom:tenantId"]
        user_role = response["custom:userRole"]
    
    
    tmp = event['methodArn'].split(':')
    api_gateway_arn_tmp = tmp[5].split('/')
    aws_account_id = tmp[4]    
    
    policy = AuthPolicy(principal_id, aws_account_id)
    policy.restApiId = api_gateway_arn_tmp[0]
    policy.region = tmp[3]
    policy.stage = api_gateway_arn_tmp[1]

    if (auth_manager.isSaaSProvider(user_role) == False):
        if (isTenantAuthorizedForThisAPI(apigateway_url, api_gateway_arn_tmp[0]) == False):
            logger.error('Unauthorized')
            raise Exception('Unauthorized')

    #roles are not fine-grained enough to allow selectively
    policy.allowAllMethods()        
    
    authResponse = policy.build()
 
    #   Generate STS credentials to be used for FGAC
    
    #   Important Note: 
    #   We are generating STS token inside Authorizer to take advantage of the caching behavior of authorizer
    #   Another option is to generate the STS token inside the lambda function itself, as mentioned in this blog post: https://aws.amazon.com/blogs/apn/isolating-saas-tenants-with-dynamically-generated-iam-policies/
    #   Finally, you can also consider creating one Authorizer per microservice in cases where you want the IAM policy specific to that service 
    
    iam_policy = auth_manager.getPolicyForUser(user_role, utils.Service_Identifier.BUSINESS_SERVICES.value, tenant_id, region, aws_account_id)
    logger.info(iam_policy)
    
    role_arn = "arn:aws:iam::{}:role/authorizer-access-role".format(aws_account_id)
    
    assumed_role = sts_client.assume_role(
        RoleArn=role_arn,
        RoleSessionName="tenant-aware-session",
        Policy=iam_policy,
    )
    credentials = assumed_role["Credentials"]

    #pass sts credentials to lambda
    context = {
        'accesskey': credentials['AccessKeyId'], # $context.authorizer.key -> value
        'secretkey' : credentials['SecretAccessKey'],
        'sessiontoken' : credentials["SessionToken"],
        'userName': user_name,
        'tenantId': tenant_id,
        'userPoolId': userpool_id,
        #TODO: Assign API Key to authorizer response
        #'apiKey': api_key,
        'userRole': user_role
    }
    
    authResponse['context'] = context
    authResponse['usageIdentifierKey'] = api_key
    
    return authResponse