示例#1
0
def test_premature_put():
    LOG_STREAM.truncate(0)
    LOG_STREAM.seek(0)
    ContextLog.clear()
    with pytest.raises(RuntimeError) as excinfo:
        ContextLog.put_request_id('xyz')
    assert "Don't call put before get_logger!" in str(excinfo.value)
示例#2
0
def test_premature_get_map():
    LOG_STREAM.truncate(0)
    LOG_STREAM.seek(0)
    ContextLog.clear()
    with pytest.raises(RuntimeError) as ex:
        ContextLog.get_map()
    assert "Don't call get_map before get_logger!" in str(ex.value)
示例#3
0
def user():
  """
  The guest entry point
  """
  log = ContextLog.get_logger('user')

  log.info('User request')

  return jsonify(status=200, message='OK')
示例#4
0
def test_sub_module():
    LOG_STREAM.truncate(0)
    LOG_STREAM.seek(0)
    log = ContextLog.get_logger('test_sub_module', True)
    sub_module_function()
    log.info('sub_module_function')
    entry = json.loads(LOG_STREAM.getvalue())
    assert entry['message'] == 'sub_module_function'
    assert 'contextMap' in entry
    assert entry['contextMap']['request-id'] == 'modulexyz'
示例#5
0
def delete_user_pool_domain(domain):
    """
    Function to delete user pool domain
    """
    log = ContextLog.get_logger('delete_user_pool_domain')

    response = COGNITO_IDP_CLIENT.describe_user_pool_domain(Domain=domain)

    if 'UserPoolId' in response['DomainDescription']:
        log.info('domain exists - deleting: %s', domain)
        COGNITO_IDP_CLIENT.delete_user_pool_domain(
            Domain=domain,
            UserPoolId=response['DomainDescription']['UserPoolId'])
示例#6
0
def check_email_valid(email):
    """
  Check if email address is lower-case and valid as per the
  username_validator package
  """

    log = ContextLog.get_logger('check_email_valid')

    if email.islower():
        log.info('check_email_valid: email address is lower-case')
    else:
        log.warning('check_email_valid: email address is not all lower-case')
        raise Exception('Email must be lowercase')

    # Will raise and exception if invalid
    USERNAME_VALIDATOR.validate_all(email)
示例#7
0
def check_email_domain_valid(email):
    """
  Check if email domain is in the exposable email domain list
  """

    log = ContextLog.get_logger('check_email_domain_valid')

    address = email.strip().split('@')

    if address[1] not in EMAIL_DOMAIN_BLACKLIST:
        log.info(
            'check_email_domain_valid: email domain is not in disposable email domain list'
        )
    else:
        log.warning(
            'check_email_domain_valid: email domain is in disposable email domain list'
        )
        raise Exception('Email domain is disposable')
示例#8
0
def send(event,
         context,
         responseStatus,
         response_data,
         physicalResourceId=None,
         noEcho=False):
    """
    From: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html
    """
    log = ContextLog.get_logger('send')

    responseUrl = event['ResponseURL']

    responseBody = {}
    responseBody['Status'] = responseStatus
    responseBody[
        'Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name
    responseBody[
        'PhysicalResourceId'] = physicalResourceId or context.log_stream_name
    responseBody['StackId'] = event['StackId']
    responseBody['RequestId'] = event['RequestId']
    responseBody['LogicalResourceId'] = event['LogicalResourceId']
    responseBody['NoEcho'] = noEcho
    responseBody['Data'] = response_data

    json_responseBody = json.dumps(responseBody)

    log.info('Response body: %s', json_responseBody)

    headers = {
        'content-type': '',
        'content-length': str(len(json_responseBody))
    }

    try:
        response = requests.put(responseUrl,
                                data=json_responseBody,
                                headers=headers)
        log.info('Status code: ' + response.reason)
    except Exception as ex:
        log.error('send(..) failed executing requests.put(..): %s', str(ex))
示例#9
0
def lambda_handler(event, context):

    log = ContextLog.get_logger('lambda_handler', True)
    ContextLog.put_start_time()
    ContextLog.put_request_id(context.aws_request_id)
    log.info('start')

    output = []

    try:

        for record in event['records']:

            payload = base64.b64decode(record['data']).decode()

            log.info('Processing request id: %s', record['recordId'])

            # Transform time to isoformat and add to record
            d = json.loads(payload)
            t = datetime.strptime(d['datetime'], "%d/%b/%Y:%H:%M:%S %z")
            d['datetimeiso'] = t.isoformat()

            payload = json.dumps(d) + '\n'

            output_record = {
                'recordId': record['recordId'],
                'result': 'Ok',
                'data': base64.b64encode(payload.encode()).decode()
            }
            output.append(output_record)

        log.info('Successfully processed records: %d', len(event['records']))

    except:
        log.exception('Unexpected error')
        raise
    finally:
        ContextLog.put_end_time()
        log.info('Request: end')

    return {'records': output}
示例#10
0
def handler(event, context):
  """
  The Lambda handler entry point
  """

  log = ContextLog.get_logger('handler', True)
  log.setLevel(os.environ.get('LOG_LEVEL', 'DEBUG'))

  ContextLog.put_start_time()
  ContextLog.put_request_id(context.aws_request_id)

  log.info('Request: start - event %s', json.dumps(event))

  try:
    log.info('Request: running')

    return awsgi.response(app, event, context)

  except:
    log.exception('Unexpected exception')
    raise
  finally:
    ContextLog.put_end_time()
    log.info('Request: end')
示例#11
0
def test_thread_context():
    LOG_STREAM.truncate(0)
    LOG_STREAM.seek(0)
    log = ContextLog.get_logger('test_thread_context', True)

    ContextLog.put_start_time()
    sleep(0.1)  # Short delay to test for sane duration range
    ContextLog.put('arbitrary', 'value')
    ContextLog.put_request_id('xyz')
    ContextLog.put_request_method('POST')
    ContextLog.put_request_path('/arbitrary')
    ContextLog.put_response_status('200')
    ContextLog.put_end_time()
    ContextLog.put_request_user_id('myuser')
    ContextLog.put_request_client_id('clientid')
    ContextLog.put_request_primary_ip('5.3.2.1')
    ContextLog.put_request_client_ip('1.2.3.5')
    ContextLog.put_request_viewer_country('dk')
    ContextLog.put_trigger_source('Event')

    log.debug('thread_context')
    entry = json.loads(LOG_STREAM.getvalue())
    assert entry['message'] == 'thread_context'
    assert 'contextMap' in entry
    assert entry['contextMap']['arbitrary'] == 'value'
    assert entry['contextMap']['request-id'] == 'xyz'
    assert entry['contextMap']['request-method'] == 'POST'
    assert entry['contextMap']['request-path'] == '/arbitrary'
    assert entry['contextMap']['response-status'] == '200'
    assert entry['contextMap']['start-time']
    assert entry['contextMap']['epoch-start-time']
    assert entry['contextMap']['end-time']
    assert entry['contextMap']['epoch-end-time']
    assert 100 <= entry['contextMap']['duration'] <= 500
    assert entry['contextMap']['user-id'] == 'myuser'
    assert entry['contextMap']['client-id'] == 'clientid'
    assert entry['contextMap']['primary-ip'] == '5.3.2.1'
    assert entry['contextMap']['client-ip'] == '1.2.3.5'
    assert entry['contextMap']['viewer-country'] == 'dk'
    assert entry['contextMap']['trigger-source'] == 'Event'

    assert ContextLog.get('trigger-source') == 'Event'

    assert ContextLog.get_map()
示例#12
0
def sub_function():
    ContextLog.put_request_id('xyz123')
示例#13
0
def handler(event, context):
    """
    Lambda main handler
    """
    log = ContextLog.get_logger('handler', True)

    ContextLog.put_start_time()
    ContextLog.put_request_id(context.aws_request_id)

    try:
        log.info('Request: start - event %s', json.dumps(event))

        user_pool_id = event['ResourceProperties']['UserPoolId']
        domain = event['ResourceProperties']['Domain']
        custom_domain_config = None

        if 'CustomDomainConfig' in event['ResourceProperties']:
            custom_domain_config = event['ResourceProperties'][
                'CustomDomainConfig']
            log.info('Contains custom domain config found: %s',
                     json.dumps(custom_domain_config))
            certificate_arn = custom_domain_config['CertificateArn']

            # Hack to support Secrets Manager as Cloudformation custom
            # resources do not presently support parameter resolution
            res = re.match(
                '{{resolve:secretsmanager:(.+):SecretString:([a-zA-Z0-9-_:]+)}}',
                certificate_arn)
            if res:
                secret_id = res[1]
                attrib_str = res[2].split(':')
                secret_attribute = attrib_str[0] if len(
                    attrib_str) > 0 else None
                args = {}
                if len(attrib_str) > 1:
                    args['VersionId'] = attrib_str[1]
                if len(attrib_str) > 2:
                    args['VersionStage'] = attrib_str[2]
                secret_response = SECRETSMANAGER_CLIENT.get_secret_value(
                    SecretId=secret_id, **args)

                secret_obj = json.loads(secret_response['SecretString'])
                attribute_value = secret_obj[secret_attribute]

                log.info('Replacing certificate arn with SecretString: ...%s',
                         attribute_value[-5:])

                custom_domain_config['CertificateArn'] = attribute_value

        response = None
        response_data = dict()

        if event['RequestType'] == 'Create':
            response = COGNITO_IDP_CLIENT.create_user_pool_domain(
                Domain=domain,
                UserPoolId=user_pool_id,
                CustomDomainConfig=custom_domain_config)
            response_data['Data'] = 'Created'

        elif event['RequestType'] == 'Update':

            # If domain name needs to be updated then we need to
            # delete the old domain and then create the new domain
            if 'OldResourceProperties' in event and event[
                    'OldResourceProperties']['Domain'] != event[
                        'ResourceProperties']['Domain']:
                delete_user_pool_domain(
                    event['OldResourceProperties']['Domain'])

            response = COGNITO_IDP_CLIENT.create_user_pool_domain(
                Domain=domain,
                UserPoolId=user_pool_id,
                CustomDomainConfig=custom_domain_config)
            response_data['Data'] = 'Updated'

        elif event['RequestType'] == 'Delete':
            delete_user_pool_domain(event['ResourceProperties']['Domain'])
            response_data['Data'] = 'Deleted'

        else:
            send(event, context, FAILED,
                 {'Data': 'Unexpected: {}'.format(event['RequestType'])})
            return

        if response and 'CloudFrontDomain' in response:
            log.info(
                'create_user_pool_domain response includes CloudFrontDomain: %s',
                response['CloudFrontDomain'])
            response_data['CloudFrontDomain'] = response['CloudFrontDomain']

        send(event, context, SUCCESS, response_data)

        log.info('CognitoUserPoolDomain Success for request type %s',
                 event['RequestType'])

    except Exception as ex:
        log.exception('Unexpected exception')
        send(event, context, FAILED, {'Data': str(ex)})
        raise
    finally:
        ContextLog.put_end_time()
        log.info('Request: end')
示例#14
0
def handler(event, context):
    """
  The Lambda handler entry point
  Called when a user is confirmed (link or email verification)
  """

    log = ContextLog.get_logger('handler', True)
    log.setLevel(os.environ.get('LOG_LEVEL', "DEBUG"))

    ContextLog.put_start_time()
    ContextLog.put_request_id(context.aws_request_id)
    ContextLog.put_request_user_id(event['request']['userAttributes']['email'])
    ContextLog.put_request_client_id(event['callerContext']['clientId'])
    ContextLog.put_trigger_source(event['triggerSource'])

    # Log event - but remove any sensitive information
    user_event = deepcopy(event)

    log.info('Request: start - event %s', json.dumps(user_event))

    try:
        log.info('Processing: %s', event['triggerSource'])

        if event['triggerSource'] == 'PostConfirmation_ConfirmSignUp':

            user_event['result'] = 'CONFIRM_SIGNUP_SUCCESS'

        elif event[
                'triggerSource'] == 'PostConfirmation_ConfirmForgotPassword':
            user_event['result'] = 'CONFIRM_FORGOT_PASSWORD_SUCCESS'

    except:
        log.exception('Unexpected exception')
        user_event['result'] = 'ERROR'
        raise
    finally:
        publish_user_event(user_event)
        ContextLog.put_end_time()
        log.info('Request: end')

    return event
示例#15
0
def sub_module_function():
    ContextLog.put_request_id('modulexyz')
示例#16
0
def handler(event, context):
    """
  The Lambda handler entry point
  Called when a user is confirmed (link or email verification)
  """

    log = ContextLog.get_logger('handler', True)
    log.setLevel(os.environ.get('LOG_LEVEL', "DEBUG"))

    ContextLog.put_start_time()
    ContextLog.put_request_id(context.aws_request_id)
    ContextLog.put_request_user_id(event['request']['userAttributes']['email'])
    ContextLog.put_request_client_id(event['callerContext']['clientId'])
    ContextLog.put_trigger_source(event['triggerSource'])

    # Log event but remove any sensitive information
    user_event = deepcopy(event)

    log.info('Request: start - event %s', json.dumps(user_event))

    try:
        email = event['request']['userAttributes']['email']

        check_email_valid(email)

        # We don't validate the email domain if it's an Admin call.
        # The Admin call is made during user migration and we allow
        # them through.
        if event['triggerSource'] == 'PreSignUp_AdminCreateUser':
            log.info('handler: Admin call does not validate domain')
        else:
            check_email_domain_valid(email)

    except:
        log.exception('Invalid email')
        raise
    finally:
        ContextLog.put_end_time()
        log.info('Request: end')

    return event