通过OAuth2和Python MSAL库进行Office 365 IMAP身份验证

z9zf31ra  于 2022-10-08  发布在  Python
关注(0)|答案(2)|浏览(433)

bounty将在12小时后到期。这个问题的答案有资格获得+500的声誉赏金。quickshiftin正在寻找一个规范的答案:这个问题应该适用于广泛的受众,因为微软目前不建议使用基本身份验证,而Python可能是世界上最流行的编程语言。

我正在尝试升级一个传统的邮件机器人,以通过OAuth2进行身份验证,而不是基本身份验证,因为它是now deprecated two days from now

该文档规定,应用程序可以保留其原始逻辑,而只交换身份验证位
构建了使用这些协议发送、阅读或以其他方式处理电子邮件的应用程序的应用程序开发人员将能够保持相同的协议,但需要为其用户实现安全、现代的身份验证体验。此功能构建在Microsoft Identity Platform v2.0之上,并支持访问Microsoft 365电子邮件帐户。

请注意,我显式选择了client credentials flow,因为文档说明

这种类型的授权通常用于服务器到服务器的交互,这些交互必须在后台运行,而不会立即与用户交互。

因此,我有一个使用MSAL python library检索访问令牌的python脚本。现在,我正在尝试使用该访问令牌向IMAP服务器进行身份验证。有一些现有的线程显示如何连接到Google,我想我的情况非常接近this one,除了我连接的是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=%s1auth=Bearer %s11' % (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)

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.

你知道我可能会错在哪里吗,或者如何从IMAP服务器获得关于身份验证失败原因的更可靠的信息?

我看过的东西

  • 注意this answer不再起作用,因为建议的作用域无法生成访问令牌。
  • 客户端凭据流似乎授权https://graph.microsoft.com/.default授予。我不确定这是否包括IMAP资源ehttps://outlook.office.com/IMAP.AccessAsUser.All所需的作用域?
  • 根据MS文档上的示例,已验证从Google线程提升的代码是否正确生成SASL XOAUTH2字符串
import base64

user = 'test@contoso.onmicrosoft.com'
token = 'EwBAAl3BAAUFFpUAo7J3Ve0bjLBWZWCclRC3EoAA'

xoauth = "user=%s1auth=Bearer %s11" % (user, token)

xoauth = xoauth.encode('ascii')
xoauth = base64.b64encode(xoauth)
xoauth = xoauth.decode('ascii')

xsanity = 'dXNlcj10ZXN0QGNvbnRvc28ub25taWNyb3NvZnQuY29tAWF1dGg9QmVhcmVyIEV3QkFBbDNCQUFVRkZwVUFvN0ozVmUwYmpMQldaV0NjbFJDM0VvQUEBAQ=='

print(xoauth == xsanity) # prints True
  • This thread似乎建议需要获取多个令牌,一个用于GRAPE,另一个用于IMAP连接;这是我遗漏的吗?
w46czmvw

w46czmvw1#

尝试使用此脚本:

import json
import msal

import requests

client_id = '***'
client_secret = '***'
tenant_id = '***'
authority = f"https://login.microsoftonline.com/{tenant_id}"

app = msal.ConfidentialClientApplication(
    client_id=client_id,
    client_credential=client_secret,
    authority=authority)

scopes = ["https://graph.microsoft.com/.default"]

result = None
result = app.acquire_token_silent(scopes, account=None)

if not result:
    print(
        "No suitable token exists in cache. Let's get a new one from Azure Active Directory.")
    result = app.acquire_token_for_client(scopes=scopes)

# if "access_token" in result:

# print("Access token is " + result["access_token"])

if "access_token" in result:
    userId = "***"
    endpoint = f'https://graph.microsoft.com/v1.0/users/{userId}/sendMail'
    toUserEmail = "***"
    email_msg = {'Message': {'Subject': "Test Sending Email from Python",
                             'Body': {'ContentType': 'Text', 'Content': "This is a test email."},
                             'ToRecipients': [{'EmailAddress': {'Address': toUserEmail}}]
                             },
                 'SaveToSentItems': 'true'}
    r = requests.post(endpoint,
                      headers={'Authorization': 'Bearer ' + result['access_token']}, json=email_msg)
    if r.ok:
        print('Sent email successfully')
    else:
        print(r.json())
else:
    print(result.get("error"))
    print(result.get("error_description"))
    print(result.get("correlation_id"))

来源:https://kontext.tech/article/795/python-send-email-via-microsoft-graph-api

uwopmtnx

uwopmtnx2#

也许可以尝试login而不是authenticate

这似乎就是这个答案背后的逻辑--PythonImalib Gmail身份验证:

imap.login('bobdole@gmail.com', 'Bob Dole likes your style!')

另外,您是否检查了您的权限范围字符串?根据您在上的链接文档。文档提到IMAP的权限范围字符串:

https://outlook.office.com/IMAP.AccessAsUser.All

相关问题