I'm trying to implement Cognito MFA using email. Following the documentation here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-sms-sender.html
I'm using a Python lambda that gets triggered by Cognito when the user enters their user+pass. However, I'm getting the following error with the aws-encryption-sdk-python library:
Traceback (most recent call last):
File "/var/task/aws_encryption_sdk/internal/formatting/deserialize.py", line 87, in _verified_version_from_id
return SerializationVersion(version_id)
File "/var/lang/lib/python3.9/enum.py", line 384, in __call__
return cls.__new__(cls, value)
File "/var/lang/lib/python3.9/enum.py", line 702, in __new__
raise ve_exc
ValueError: 65 is not a valid SerializationVersion
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/var/task/aws_encryption_sdk/__init__.py", line 186, in decrypt
plaintext = decryptor.read()
File "/var/task/aws_encryption_sdk/streaming_client.py", line 250, in read
self._prep_message()
File "/var/task/aws_encryption_sdk/streaming_client.py", line 782, in _prep_message
self._header, self.header_auth = self._read_header()
File "/var/task/aws_encryption_sdk/streaming_client.py", line 797, in _read_header
header, raw_header = deserialize_header(self.source_stream, self.config.max_encrypted_data_keys)
File "/var/task/aws_encryption_sdk/internal/formatting/deserialize.py", line 336, in deserialize_header
version = _verified_version_from_id(version_id)
File "/var/task/aws_encryption_sdk/internal/formatting/deserialize.py", line 89, in _verified_version_from_id
raise NotSupportedError("Unsupported version
{}
".format(version_id), error)
aws_encryption_sdk.exceptions.NotSupportedError: ('Unsupported version 65', ValueError('65 is not a valid SerializationVersion'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/var/task/aws_encryption_sdk/streaming_client.py", line 218, in __exit__
self.close()
File "/var/task/aws_encryption_sdk/streaming_client.py", line 985, in close
raise SerializationError("Footer not read")
aws_encryption_sdk.exceptions.SerializationError: Footer not read
I'm not setting any version 65 anywhere. This is my code and I already verified the env vars are passed correctly:
import os
import json
import boto3
from botocore.exceptions import ClientError
from common.utils import *
from common.sqlUtils import *
from common.authentication import *
from common.authorization import *
from common.exceptions import GeneralException
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
import aws_encryption_sdk
from aws_encryption_sdk.identifiers import CommitmentPolicy
# Configure the encryption SDK client with the KMS key from the environment variables.
awsEncryptionSdkClient = aws_encryption_sdk.EncryptionSDKClient(
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)
decryptionKeyArn = os.environ["cognitoCodeEncryptionKeyArn"]
kms_key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(
key_ids=[decryptionKeyArn]
)
def sendEmail(event, context):
try:
#TODO check if email is verified, user is confirmed, etc
plaintextCode = None
if "request" in event and "code" in event["request"]:
print("Line 35: ", event)
encryptedCode = event["request"]["code"]
print("encryptedCode: ", encryptedCode)
print("decryptionKeyArn ", decryptionKeyArn)
plaintextCode, plaintextHeader = awsEncryptionSdkClient.decrypt(
source=encryptedCode,
key_provider=kms_key_provider
)
print("plaintextCode:", plaintextCode)
subject = None
html_content = None
if plaintextCode is not None:
subject = 'Code'
html_content = f'<strong>Your code is: {plaintextCode}</strong>'
message = Mail(
from_email='no-reply@mydomain.com',
to_emails=event["request"]["userAttributes"]["email"],
subject=subject,
html_content=html_content
)
sendgridSecret = getSecret(os.environ['cognitoSendgridSecretArn'])
if isJson(sendgridSecret):
sendgridSecret = json.loads(sendgridSecret)['SENDGRID_API_KEY']
sg = SendGridAPIClient(sendgridSecret)
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
#TODO check if email was sent successfully
return json_response({"sendgrid message": response})
except Exception as e:
httpCode = 500
if isinstance(e, GeneralException):
httpCode = e.httpCode
print(str(e))
return json_response({"message": str(e)}, httpCode)
Any pointers would be appreciated!
When the cipher text code is provided to the lambda function, it is base64 encoded. When passing the encrypted code in here, it needs to be base64 decoded and converted into binary.
import base64
...
plaintextCode, plaintextHeader = awsEncryptionSdkClient.decrypt(
source=base64.b64decode(encryptedCode),
key_provider=kms_key_provider
)