2 Answers
- Newest
- Most votes
- Most comments
0
Hello.
Can I view users registered in the Cognito user pool?
If the user can be displayed, it is likely that the password migration from RDS has not been successful.
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cognito-idp/list-users.html
The following documents may be useful for user migration.
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html
0
This is the main.py that handles the migration when the AWS Lambda gets triggered when a user is signing in and he's not in the Cognito User Pool:
import json
from django.conf import settings
from django.contrib.auth.hashers import check_password
import boto3
import psycopg2
import uuid
# Set the PASSWORD_HASHERS setting to be called when authenticated. This is NECESSARY since we are working outside a Django project:
settings.configure(
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
],
DEBUG=True, # Set DEBUG to your desired value
)
def get_db_credentials(secret_name):
session = boto3.session.Session()
client = session.client(service_name='secretsmanager')
response = client.get_secret_value(SecretId=secret_name)
secret = json.loads(response['SecretString'])
return secret
def authenticate_user(user_email, password, user_auth_table, db_data):
try:
connection = psycopg2.connect(
dbname=db_data["DATABASE_NAME"],
user=db_data["DATABASE_USER"],
password=db_data["DATABASE_PASSWORD"],
host=db_data["DATABASE_HOST"],
port=db_data["DATABASE_PORT"]
)
cursor = connection.cursor()
# Fetch hashed password and user's email from the database:
cursor.execute(f"SELECT password, username, email, is_app1_user, is_app2_userFROM {user_auth_table} WHERE email = '{user_email}'")
result = cursor.fetchone()
user = {
"email": result[2],
"username": result[1],
"password": password,
"is_app1_user": result[3],
"is_app2_user": result[4]
}
if not result:
raise Exception("User not found")
hashed_password = result[0]
# Use Django's check_password to validate:
if not check_password(password, hashed_password):
raise Exception("Incorrect password")
return {
'statusCode': 200,
'body': {
'message': "Authentication successful",
'user': user
}
}
except Exception as e:
print("Error during authentication:", e)
return {
'statusCode': 500,
'body': {
'error': str(e)
}
}
finally:
if connection:
cursor.close()
connection.close()
def lambda_handler(event, context):
# Check the trigger source, for this we need the "UserMigration_Authentication" trigger
print("EVENT: ", event)
if event['triggerSource'] == 'UserMigration_Authentication':
# Get the user name and password from the event (need to check wheter we need the Django's secret key or not)
user_email = event['userName'] # userName comes from Cognito, so if we are using email, userName will be the email.
password = event['request']['password']
# We need the "client_id" to check whether the request is coming from App1 or App2:
client_id = event['callerContext']['clientId']
if client_id == 'cs40****2bj1v***************':
app = 'app2'
elif client_id == 'NEED_TO_CREATE_THE_OTHER_APP_CLIENT_ID':
app = 'app1'
# Checking in the logs it's accessing the right app:
print("APP: ", app)
# Connect to the DB depending if the request comes from app1 or app2:
if app == "app2":
# Get the credentials from the AWS Secrets Manager
db_credentials = get_db_credentials(secret_name='my_secret_name')
print("DB USER: ", db_credentials['username'])
db_data = {
"DATABASE_NAME": '*******',
"DATABASE_USER": db_credentials['username'],
"DATABASE_PASSWORD": db_credentials['password'],
"DATABASE_HOST": '********************************', # Here I used the Writer type
"DATABASE_PORT": '****'
}
# Attempt to authenticate against the Django database:
result = authenticate_user(user_email=user_email, password=password, user_auth_table="public.interface_customuser", db_data=db_data)
elif app == "app1":
# Here I'll need to setup the app1's db connection
pass
user = result["body"]["user"]
if user:
print("USER: ", user)
# If authentication was successful, populate the user attributes for Cognito
# Here, adjust the attribute names and fetch logic according to your model and requirements
event['response']['userAttributes'] = {
'username': user["username"],
'password': user["password"],
'email': user["email"],
'email_verified': 'true',
'custom:is_app1_user': 1, # This is because I've set these custom attributes as number (1 or 0)
'custom:is_app2_user': 1
}
# If using Django's default password hasher, the first part of the encoded password is the used algorithm.
event['response']['finalUserStatus'] = 'CONFIRMED'
event['response']['messageAction'] = 'SUPPRESS' # This ensures that Amazon Cognito won't send an SMS or email for verification
event['response']['desiredDeliveryMediums'] = ['EMAIL']
print(event)
return event
else:
# If authentication fails:
raise Exception(f"Not a {app} user or password incorrect")
And this is the Event it returns (I printed it to see) when checking the logs in Cloudwatch:
{'version': '1', 'triggerSource': 'UserMigration_Authentication', 'region': 'eu-west-2', 'userPoolId': 'eu-west-2_the_right_user_pool_id', 'userName': 'andres**********@gmail.com', 'callerContext': {'awsSdkVersion': 'aws-sdk-unknown-unknown', 'clientId': 'cs40****2bj1v***************'}, 'request': {'password': '***********', 'validationData': None, 'userAttributes': None}, 'response': {'userAttributes': {'username': 'andres**********', 'password': '***********', 'email': 'andres**********@gmail.com', 'email_verified': 'true', 'custom:is_app1_user': 1, 'custom:is_app2_user': 1}, 'forceAliasCreation': None, 'enableSMSMFA': None, 'finalUserStatus': 'CONFIRMED', 'messageAction': 'SUPPRESS', 'desiredDeliveryMediums': ['EMAIL']}}
answered 7 months ago
Relevant content
- asked a year ago
- asked 9 months ago
- AWS OFFICIALUpdated 2 years ago
- AWS OFFICIALUpdated 5 months ago
- AWS OFFICIALUpdated 8 months ago
- AWS OFFICIALUpdated a year ago
Hello, sorry for the delay, but I've been reading those posts and trying some other possible solutions as checking the permission policies for the role, adding the password in the event['response']['userAttributes'], among other things, but it still doesn't migrate the user, and I don't understand why since the code doesn't throw any errors. I'll add the code I'm using below as an answer, so that you would have more context to determine is there's something wrong in my code (I know that adding the password might not be okay, but without that I get the same result too, I was trying)
As for your question, after the lambda finishes the process, I can't see the user that supposedly migrated in the user pool. But the users that were created directly using Cognito (not migration), those I can see in the User Pool.