python-3.x - AWS Cognito 90 天自动密码轮换
问题描述
我需要创建一个自动密码重置脚本。我创建了一个自定义字段以尝试跟踪它,并希望我可以访问一些标准字段。此脚本应找到符合以下条件的用户:
以下 3 个日期中的任何一个 >= 90 天前的最新日期:Sign_Up、Forgot_Password 或 custom:pwdCreateDate
除了出现在 admin_list_user_auth_events 中的忘记密码并且该响应不包括响应中的用户名之外,我似乎找不到任何 boto3 cognito 客户端获取有关此信息的方法。我想既然你提供了用户名来获取事件,你可以想办法从事件中找到最新的忘记密码并将其与用户名联系起来。
是否有其他人实施了任何 boto3 自动化来设置帐户以根据这些字段中的任何一个强制重置密码?
解决方案
这是我登陆的地方,请理解 coginito 有一些限制,这使得真正完美的密码轮换变得困难。还知道您是否可以使脚本更高效,因为在 lambda 中,由于管理 API 上的 5RPS,您可能会超时超过大约 350 个用户。
先决条件:将 lambda 函数设置为 5 并发,否则您将超过 5RPS 的限制。您的 cognito 用户池属性中的 1 个可变字段,用于放入日期。自定义 lambda zip 文件,其中包括保存到 s3 的熊猫。
import os
import sys
# this adds the parent directory of bin so we can find the module
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
sys.path.append(parent_dir)
#This addes venv lib/python2.7/site-packages/ to the search path
mod_path = os.path.abspath(parent_dir+"/lib/python"+str(sys.version_info[0])+"."+str(sys.version_info[1])+"/site-packages/")
sys.path.append(mod_path)
import boto3
import datetime
import pandas as pd
import time
current_path = os.path.dirname(os.path.realpath(__file__))
# Use this one for the parent directory
ENV_ROOT = os.path.abspath(os.path.join(current_path, os.path.pardir))
# Use this one for the current directory
#ENV_ROOT = os.path.abspath(os.path.join(current_path))
sys.path.append(ENV_ROOT)
#if __name__ == "__main__":
def lambda_handler(event, context):
user_pool_id = os.environ['USER_POOL_ID']
idp_client = boto3.client('cognito-idp')
users_list = []
page_token = None
dateToday = datetime.datetime.today().date()
def update_user(user) :
idp_client.admin_update_user_attributes(
UserPoolId = user_pool_id,
Username = user,
UserStatus = 'RESET_REQUIRED',
UserAttributes = [
{
'Name': 'custom:pwdCreateDate',
'Value': str(dateToday)
}
]
)
users = idp_client.list_users(
UserPoolId = user_pool_id
)
for user in users['Users']: users_list.append(user['Username'])
page_token = users['PaginationToken']
while 'PaginationToken' in users :
users = idp_client.list_users(
UserPoolId = user_pool_id,
PaginationToken = page_token
)
for user in users["Users"]: users_list.append(user["Username"])
if 'PaginationToken' in users :
page_token = users['PaginationToken']
attrPwdDates = []
for i in range(len(users_list)) :
userAttributes = idp_client.admin_get_user(
UserPoolId = user_pool_id,
Username = users_list[i]
)
for a in userAttributes['UserAttributes'] :
if a['Name'] == 'custom:pwdCreateDate' :
attrPwdDates.append(datetime.datetime.strptime(a['Value'], '%Y-%m-%d %H:%M:%S.%f').date())
time.sleep(1.0)
list_of_userattr_tuples = list(zip(users_list, attrPwdDates))
df1 = pd.DataFrame(list_of_userattr_tuples,columns = ['Username','Password_Last_Set'])
authPwdDates = []
for i in range(len(users_list)) :
authEvents = idp_client.admin_list_user_auth_events(
UserPoolId = user_pool_id,
Username = users_list[i]
)
for event in authEvents['AuthEvents'] :
if event['EventType'] == 'ForgotPassword' and event['EventResponse'] == 'Pass' :
authPwdDates.append(event['CreationDate'].date())
break
time.sleep(1.0)
list_of_userauth_tuples = list(zip(users_list, authPwdDates))
df2 = pd.DataFrame(list_of_userauth_tuples,columns = ['Username','Password_Last_Forgot'])
df3 = df1.merge(df2,how='left', on = 'Username')
df3[['Password_Last_Set','Password_Last_Forgot']] = df3[['Password_Last_Set','Password_Last_Forgot']].apply(pd.to_datetime)
cols = ['Password_Last_Set','Password_Last_Forgot']
df4 = df3.loc[df3[cols].max(axis=1)<=pd.Timestamp.now() - pd.Timedelta(90, unit='d'), 'Username']
for i,r in df4.iterrows() :
update_user(r['Username'])
推荐阅读
- azure-devops - 从分支触发时,触发器中特定项目的路径不起作用
- terraform - terraform 中的非空字符串是否真实?
- html - 在 Python 中将 HTML 表转换为 Pandas 数据框
- php - 从服务器调用变量到客户端的问题
- python - 从df创建字典的正确方法或计算jaccard相似度的方法
- python - 熊猫索引 StringMethods 失去索引
- angular - 如何以角度调整base64图像的大小
- python - Keras嵌入层能否为某个索引(例如:-1)提供随机向量而不是固定向量
- ruby-on-rails - Select2 在表单 POST 后获得多项选择
- focus - 使用 Brightscript 使用两个文本框和按钮保持焦点