qui*_*tin 21 python email imap oauth-2.0 office365
我正在尝试升级旧版邮件机器人以通过 Oauth2 而不是基本身份验证进行身份验证,因为它现在已在两天后被弃用。
该文档指出应用程序可以保留其原始逻辑,同时仅交换身份验证位
使用这些协议构建发送、阅读或以其他方式处理电子邮件的应用程序的应用程序开发人员将能够保留相同的协议,但需要为其用户实现安全、现代的身份验证体验。此功能构建在 Microsoft Identity 平台 v2.0 之上,支持访问 Microsoft 365 电子邮件帐户。
注意我已经明确选择了客户端凭据流程,因为文档指出
这种类型的授权通常用于必须在后台运行的服务器到服务器交互,而不需要立即与用户交互。
因此,我有一个 python 脚本,可以使用MSAL python 库检索访问令牌。现在我尝试使用该访问令牌向 IMAP 服务器进行身份验证。有一些现有的线程展示了如何连接到 Google,我想我的情况与此非常接近,只是我正在连接到 Office 365 IMAP 服务器。这是我的脚本
import imaplib
import msal
import logging
app = msal.ConfidentialClientApplication(
'client-id',
authority='https://login.microsoftonline.com/tenant-id',
client_credential='secret-key'
)
result = app.acquire_token_for_client(scopes=['https://graph.microsoft.com/.default'])
def generate_auth_string(user, token):
return 'user=%s\1auth=Bearer %s\1\1' % (user, token)
# IMAP time!
mailserver = 'outlook.office365.com'
imapport = 993
M = imaplib.IMAP4_SSL(mailserver,imapport)
M.debug = 4
M.authenticate('XOAUTH2', lambda x: generate_auth_string('user@mydomain.com', result['access_token']))
print(result)
Run Code Online (Sandbox Code Playgroud)
IMAP 身份验证失败,尽管进行了设置M.debug = 4
,但输出并不是很有帮助
22:56.53 > b'DBDH1 AUTHENTICATE XOAUTH2'
22:56.53 < b'+ '
22:56.53 write literal size 2048
22:57.84 < b'DBDH1 NO AUTHENTICATE failed.'
22:57.84 NO response: b'AUTHENTICATE failed.'
Traceback (most recent call last):
File "/home/ubuntu/mini-oauth.py", line 21, in <module>
M.authenticate("XOAUTH2", lambda x: generate_auth_string('user@mydomain.com', result['access_token']))
File "/usr/lib/python3.10/imaplib.py", line 444, in authenticate
raise self.error(dat[-1].decode('utf-8', 'replace'))
imaplib.IMAP4.error: AUTHENTICATE failed.
Run Code Online (Sandbox Code Playgroud)
知道我可能出错的地方,或者如何从 IMAP 服务器获取有关身份验证失败原因的更可靠的信息吗?
我看过的东西
请注意,此答案不再有效,因为建议的范围无法生成访问令牌。
客户端凭证流程似乎强制授权https://graph.microsoft.com/.default
。我不确定这是否包括IMAP 资源所需的范围
https://outlook.office.com/IMAP.AccessAsUser.All
?
根据MS 文档上的示例,验证从 Google 线程中提取的代码正确生成 SASL XOAUTH2 字符串
import base64
user = 'test@contoso.onmicrosoft.com'
token = 'EwBAAl3BAAUFFpUAo7J3Ve0bjLBWZWCclRC3EoAA'
xoauth = "user=%s\1auth=Bearer %s\1\1" % (user, token)
xoauth = xoauth.encode('ascii')
xoauth = base64.b64encode(xoauth)
xoauth = xoauth.decode('ascii')
xsanity = 'dXNlcj10ZXN0QGNvbnRvc28ub25taWNyb3NvZnQuY29tAWF1dGg9QmVhcmVyIEV3QkFBbDNCQUFVRkZwVUFvN0ozVmUwYmpMQldaV0NjbFJDM0VvQUEBAQ=='
print(xoauth == xsanity) # prints True
Run Code Online (Sandbox Code Playgroud)
尝试以下步骤。
\n对于客户端凭据流程,您需要在应用程序注册中分配 \xe2\x80\x9cApplication 权限\xe2\x80\x9d,而不是 \xe2\x80\x9cDelegate 权限\xe2\x80\x9d。
\n现在,您可以通过组合此访问令牌和邮箱用户名来生成 SALS 身份验证字符串,以使用 IMAP4 进行身份验证。
\n#Python代码
\ndef get_access_token():\n tenantID = \'abc\'\n authority = \'https://login.microsoftonline.com/\' + tenantID\n clientID = \'abc\'\n clientSecret = \'abc\'\n scope = [\'https://outlook.office365.com/.default\']\n app = ConfidentialClientApplication(clientID, \n authority=authority, \n client_credential = clientSecret)\n access_token = app.acquire_token_for_client(scopes=scope)\n return access_token\n\ndef generate_auth_string(user, token):\n auth_string = f"user={user}\\1auth=Bearer {token}\\1\\1"\n return auth_string\n\n#IMAP AUTHENTICATE\n imap = imaplib.IMAP4_SSL(imap_host, 993)\n imap.debug = 4\n access_token = get_access_token_to_authenticate_imap()\n imap.authenticate("XOAUTH2", lambda x:generate_auth_string(\n \'useremail\',\n access_token[\'access_token\']))\n imap.select(\'inbox\')\n
Run Code Online (Sandbox Code Playgroud)\n
发生该imaplib.IMAP4.error: AUTHENTICATE failed
错误是因为文档中的一点不太清楚。
通过 Powershell 设置服务主体时,您需要输入应用程序 ID 和对象 ID。很多人会认为,就是你在注册App的概览页面看到的Object-ID,其实不是!此时,您需要来自“Azure Active Directory -> Enterprise Applications --> Your-App --> Object-ID”的对象 ID
New-ServicePrincipal -AppId <APPLICATION_ID> -ServiceId <OBJECT_ID> [-Organization <ORGANIZATION_ID>]
Run Code Online (Sandbox Code Playgroud)
微软说:
OBJECT_ID 是用于应用程序注册的企业应用程序节点(Azure 门户)的概述页面中的对象 ID。它不是“应用程序注册概述”节点中的对象 ID。使用不正确的对象 ID 将导致身份验证失败。
当然,您需要注意 API 权限和其他内容,但这对我来说才是重点。因此,让我们再次了解一下,就像文档页面上所解释的那样。 使用 OAuth 验证 IMAP、POP 或 SMTP 连接
这就是我用来测试它的代码:
import imaplib
import msal
import pprint
conf = {
"authority": "https://login.microsoftonline.com/XXXXyourtenantIDXXXXX",
"client_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX", #AppID
"scope": ['https://outlook.office365.com/.default'],
"secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", #Key-Value
"secret-id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", #Key-ID
}
def generate_auth_string(user, token):
return f"user={user}\x01auth=Bearer {token}\x01\x01"
if __name__ == "__main__":
app = msal.ConfidentialClientApplication(conf['client_id'], authority=conf['authority'],
client_credential=conf['secret'])
result = app.acquire_token_silent(conf['scope'], account=None)
if not result:
print("No suitable token in cache. Get new one.")
result = app.acquire_token_for_client(scopes=conf['scope'])
if "access_token" in result:
print(result['token_type'])
pprint.pprint(result)
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id"))
imap = imaplib.IMAP4('outlook.office365.com')
imap.starttls()
imap.authenticate("XOAUTH2", lambda x: generate_auth_string("target_mailbox@example.com", result['access_token']).encode("utf-8"))
Run Code Online (Sandbox Code Playgroud)
设置服务主体并授予应用程序对邮箱的完全访问权限后,等待 15 - 30 分钟以使更改生效并进行测试。
归档时间: |
|
查看次数: |
21136 次 |
最近记录: |