【问题标题】:Use IMAP with XOAUTH2 and MS365 Application permissions to authenticate IMAP for a user使用具有 XOAUTH2 和 MS365 应用程序权限的 IMAP 为用户验证 IMAP
【发布时间】:2022-09-30 04:41:18
【问题描述】:

我有一个较旧的 Python 项目,它使用标准 IMAP 机制从邮箱中检索电子邮件等进行处理。不幸的是,随着 MS365 现在淘汰非 OAuth2 和非现代身份验证,我必须尝试编写一个不依赖用户凭据但具有对身份验证等的完全访问权限的应用程序,就像其他使用 OAuth2 的用户一样。

我已将 MSAL 库部分关闭,并且可以从远程获取访问令牌 - 此应用程序配置了使用客户端密码登录的工作流,并且可以访问所有用户的所有 EWS 和应用程序中的所有 IMAP.UseAsApp的权限。不过,通过应用程序集成,我可能会错误地请求信息。

该应用程序在 Azure AD 中分配给它的以下权限运行:

所述应用程序通过共享机密而不是证书进行身份验证。

我们正在拉 Outlook 范围,因为我们想使用 Office 365 Exchange Online 的 IMAP 范围并通过此令牌和 oauth 使用 IMAP 身份验证的东西,我不相信 MIcrosoft Graph API 有任何 IMAP 身份验证端点可用的机制,

这里基本上是一个例子,我试图将 MSAL OAuth2 与我的 Azure AD 中配置的应用程序链接起来,以获得有效的imap.authenticate 调用,至少弄清楚如何使用不记名令牌完成 OAuth2 部分:

import imaplib
import msal
import pprint
import base64

conf = {
    \"authority\": \"https://login.microsoftonline.com/TENANT_ID\",
    \"client_id\": \"APP_CLIENT_ID\",
    \"scope\": [\"https://outlook.office.com/.default\"],
    \"secret\": \"APP_SECRET_KEY\",
    \"secret-id\": \"APP_SECRET_KEY (for documentation purposes)\",
    \"tenant-id\": \"TENANT_ID\"
}


def generate_auth_string(user, token):
    authstr = f\"user={user}\\x01auth=Bearer {token}\".encode(\'utf-8\')
    return base64.b64encode(authstr)


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[\'scopes\'])
    
    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 time!
    imap = imaplib.IMAP4(\'outlook.office365.com\')
    imap.starttls()
    imap.authenticate(\"XOAUTH2\", lambda x: generate_auth_string(\'example@example.com\',
                                                                result[\'access_token\']))
    
    # more IMAP stuff after this, but i haven\'t gotten further than this.

每次使用AUTHENTICATE 访问有效用户的帐户时,我都会收到AUTHENTICATE failed 消息。这必须作为应用程序而不是通过委托的用户身份验证来完成的原因是因为它是一个需要访问的无头 python 应用程序很多的通过 IMAP(提取 RFC822 格式的消息)收件箱,而不仅仅是一个特定的邮箱,我们不想为单个用户生成单独的 OAuth 令牌,我们宁愿只在应用程序级别使用它。

有人知道我做错了什么吗?或者,如果有人可以为我指出一个可行的示例的正确方向,那就太好了。

    标签: python-3.x oauth-2.0 imap msal


    【解决方案1】:

    我正在尝试做类似的事情。以下更改对我有用:

    def generate_auth_string(user, token):
        return f"user={user}\x01auth=Bearer {token}\x01\x01"
    

    【讨论】:

    • 感谢您在我这边发现了这个错误。不幸的是,AUTHETNICATE 需要一个类似字节的响应,所以我仍然必须对其进行编码。它仍然在 IMAP 调用中返回“AUTHENTICATE FAILED”。所以我很困惑我在这里做错了什么。或者我是否只是将应用程序配置错误。
    • imaplib 负责 base64 编码,因此不要提供 base64 编码的字符串。我不确定bytes 是否是有效输入,但提供str 对我有用,这里建议:stackoverflow.com/a/13467538/19785964。如果提供字符串不起作用,则问题必须与 AAD 权限有关,因为如果您在代码中到达该点,则令牌是有效的。
    • 让我戳一下它,看看它是否只适用于一个字符串。如果没有,那么我将只对字符串进行 utf8 编码,以便对其字节进行编码。如果它仍然不起作用,那么我需要刺伤微软,也许让他们帮忙,因为我有 ms365 e5 订阅,这让我得到了惊人的帮助,呵呵。
    • 所以我面临同样的问题,不同之处在于我生成令牌的方式与流程docs.microsoft.com/en-us/azure/active-directory/develop/… 不同,也尝试使用 IMAP4_SSL 但结果相同,所以如果您发现问题,请分享。如果我能更快,我也会这样做。
    • @Nuncjo 您的身份验证工作流程用于用户委托,需要用户进行身份验证。由于各种原因,这是一个处理大约 12 个独立电子邮件地址的无头应用程序,我无法使用该工作流程。我提出的任何解决方案都不适用于用户委托工作流程,反之亦然,适用于我正在做的仅应用程序身份验证工作流程。
    【解决方案2】:

    由于您使用的是客户端凭据流,因此这些文档适用:Use client credentials grant flow to authenticate IMAP and POP connections。您显示向应用程序授予权限,但看起来您还需要通过为应用程序创建服务主体然后授予该服务主体的特定邮箱权限来注册服务主体作为交换。

    【讨论】:

      猜你喜欢
      • 2020-08-19
      • 2016-05-20
      • 2016-06-30
      • 2013-06-01
      • 1970-01-01
      • 2020-11-10
      • 1970-01-01
      • 2012-01-29
      • 2013-10-08
      相关资源
      最近更新 更多