当前位置: 首页 > 知识库问答 >
问题:

用于IMAP和SMTP的Office 365 XOAUTH2身份验证失败

龙欣德
2023-03-14

最近,Exchange Online已经宣布对OAuth2.0的IMAP和SMTP的支持。按照指南,我已经设置了应用程序权限以及IMAP和SMTP连接。应用程序被配置为任何组织目录(任何Azure AD Directory-multitenant)中的帐户,并使用授权代码流。

下面的URL用于授权:

  • https://login.Microsoftonline.com/organizations/oauth2/v2.0/authorize
  • https://login.microsoftonline.com/organizations/oauth2/v2.0/token

并添加了以下委托的Microsoft图形作用域:

作用域、来自代码的请求:

final List<String> scopes = Arrays.asList(
    "offline_access",
    "email",
    "openid",
    "profile",
    "User.Read",
    "Mail.ReadWrite",
    "https%3A%2F%2Foutlook.office365.com%2FIMAP.AccessAsUser.All",
    "https%3A%2F%2Foutlook.office365.com%2FSMTP.Send"
);

我成功接收访问和刷新令牌:

{
    "token_type": "Bearer",
    "scope": "email IMAP.AccessAsUser.All Mail.ReadWrite openid profile SMTP.Send User.Read",
    "expires_in": 3599,
    "ext_expires_in": 3599,
    "access_token": "edited",
    "refresh_token": "edited",
    "id_token": "edited"
}
Properties props = new Properties();
props.put("mail.imap.ssl.enable", "true");
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put("mail.imap.auth.login.disable", "true");
props.put("mail.imap.auth.plain.disable", "true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");

Session session = Session.getInstance(props);
session.setDebug(true);

String userEmail = "user@domain.onmicrosoft.com";
String accessToken = "access_token_received_on_previous_step";

final Store store = session.getStore("imaps");
store.connect("outlook.office365.com", 993, userEmail, accessToken);

它生成以下输出:

DEBUG: JavaMail version 1.6.2
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: setDebug: JavaMail version 1.6.2
DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle]
DEBUG IMAPS: mail.imap.fetchsize: 16384
DEBUG IMAPS: mail.imap.ignorebodystructuresize: false
DEBUG IMAPS: mail.imap.statuscachetimeout: 1000
DEBUG IMAPS: mail.imap.appendbuffersize: -1
DEBUG IMAPS: mail.imap.minidletime: 10
DEBUG IMAPS: enable SASL
DEBUG IMAPS: SASL mechanisms allowed: XOAUTH2
DEBUG IMAPS: closeFoldersOnStoreFailure
DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [QQBNADc...]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS MOVE ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAPS: AUTH: PLAIN
DEBUG IMAPS: AUTH: XOAUTH2
DEBUG IMAPS: protocolConnect login, host=outlook.office365.com, user=user@domain.onmicrosoft.com, password=<non-null>
DEBUG IMAPS: SASL Mechanisms:
DEBUG IMAPS:  XOAUTH2
DEBUG IMAPS: 
DEBUG IMAPS: SASL client XOAUTH2
DEBUG IMAPS: SASL callback length: 2
DEBUG IMAPS: SASL callback 0: javax.security.auth.callback.NameCallback@17046283
DEBUG IMAPS: SASL callback 1: javax.security.auth.callback.PasswordCallback@5bd03f44
A1 AUTHENTICATE XOAUTH2 dXNlcj1o...
A1 NO AUTHENTICATE failed.

Exception in thread "main" javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
    at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:732)
    at javax.mail.Service.connect(Service.java:366)

下面的代码用于连接到SMTP:

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
props.put("mail.smtp.auth.login.disable","true");
props.put("mail.smtp.auth.plain.disable","true");
props.put("mail.debug.auth", "true");

Session session = Session.getInstance(props);
session.setDebug(true);

String userEmail = "user@domain.onmicrosoft.com";
String accessToken = "access_token_received_on_previous_step";

Transport transport = session.getTransport("smtp");
transport.connect("smtp.office365.com", 587, userEmail, accessToken);

它提供了以下输出:

DEBUG: setDebug: JavaMail version 1.6.2
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.office365.com", port 587, isSSL false
220 AM5PR0701CA0005.outlook.office365.com Microsoft ESMTP MAIL Service ready at Mon, 4 May 2020 15:52:28 +0000
DEBUG SMTP: connected to host "smtp.office365.com", port: 587
EHLO ubuntu-B450-AORUS-M
250-AM5PR0701CA0005.outlook.office365.com Hello [my ip here]
250-SIZE 157286400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8
DEBUG SMTP: Found extension "SIZE", arg "157286400"
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "DSN", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "BINARYMIME", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
STARTTLS
220 2.0.0 SMTP server ready
EHLO ubuntu-B450-AORUS-M
250-AM5PR0701CA0005.outlook.office365.com Hello [my ip here]
250-SIZE 157286400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-AUTH LOGIN XOAUTH2
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8
DEBUG SMTP: Found extension "SIZE", arg "157286400"
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "DSN", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN XOAUTH2"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "BINARYMIME", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
DEBUG SMTP: protocolConnect login, host=smtp.office365.com, user=user@domain.onmicrosoft.com, password=<non-null>
DEBUG SMTP: Attempt to authenticate using mechanisms: XOAUTH2
DEBUG SMTP: Using mechanism XOAUTH2
AUTH XOAUTH2 dXNlcj1obW9kaUB...
535 5.7.3 Authentication unsuccessful [AM5PR0701CA0005.eurprd07.prod.outlook.com]

Exception in thread "main" javax.mail.AuthenticationFailedException: 535 5.7.3 Authentication unsuccessful [AM5PR0701CA0005.eurprd07.prod.outlook.com]
    at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:965)
    at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:876)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:780)
    at javax.mail.Service.connect(Service.java:366)
    null

是我做错了什么,还是微软方面对此的支持存在漏洞?

更新1:

从命令行尝试,但结果相同:

$ openssl s_client -crlf -connect outlook.office365.com:993
... connection part omitted
* OK The Microsoft Exchange IMAP4 service is ready. [QQBNADYAUAAxADkAMgBDAEEAMAAwADkAMQAuAEUAVQBSAFAAMQA5ADIALgBQAFIATwBEAC4ATwBVAFQATABPAE8ASwAuAEMATwBNAA==]
C01 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
C01 OK CAPABILITY completed.
A01 AUTHENTICATE XOAUTH2 dXNlcj1obW9kaUBjb...
A01 NO AUTHENTICATE failed.
* BYE Connection is closed. 13
read:errno=0

感谢对这篇文章的评论,我尝试了以下范围:

public static final List<String> SCOPES = Arrays.asList(
    "offline_access",
    "https%3A%2F%2Foutlook.office365.com%2FIMAP.AccessAsUser.All",
    "https%3A%2F%2Foutlook.office365.com%2FSMTP.Send"
);

它给了我下面的令牌:

js prettyprint-override">{
    "token_type": "Bearer",
    "scope": "https://outlook.office365.com/IMAP.AccessAsUser.All https://outlook.office365.com/SMTP.Send",
    "expires_in": 3599,
    "ext_expires_in": 3599,
    "access_token": "eyJ0eXAiOiJKV1....",
    "refresh_token": "OAQABAAAAAAAm...."
}

IMAP/SMTP auth是成功的,我能够阅读收件箱+发送电子邮件!

但是对于我的应用程序,我还需要几个其他作用域来使用一些MS Graph APIendpoint(读取用户配置文件、消息订阅和消息删除)。

所以我尝试了不同的范围:

public static final List<String> SCOPES = Arrays.asList(
        "offline_access",
        "User.Read",
        "Mail.ReadWrite",
        "https%3A%2F%2Foutlook.office365.com%2FIMAP.AccessAsUser.All",
        "https%3A%2F%2Foutlook.office365.com%2FSMTP.Send"
);

这给出了令牌(请注意,作用域值与实际工作的令牌不同,权限没有outlook url):

{
    "token_type": "Bearer",
    "scope": "IMAP.AccessAsUser.All Mail.ReadWrite SMTP.Send User.Read profile openid email",
    "expires_in": 3599,
    "ext_expires_in": 3599,
    "access_token": "eyJ0eXAiOiJKV1Q...",
    "refresh_token": "OAQABAAAAAAAm..."
}
A1 NO AUTHENTICATE failed.
public static final List<String> SCOPES = Arrays.asList(
        "offline_access", // or "https%3A%2F%2Fgraph.microsoft.com%2Foffline_access"
        "https%3A%2F%2Fgraph.microsoft.com%2FUser.Read",
        "https%3A%2F%2Fgraph.microsoft.com%2FMail.ReadWrite",
        "https%3A%2F%2Foutlook.office365.com%2FIMAP.AccessAsUser.All",
        "https%3A%2F%2Foutlook.office365.com%2FSMTP.Send"
);
{
    "error": "invalid_request",
    "error_description": "AADSTS28000: Provided value for the input parameter scope is not valid because it contains more than one resource. Scope offline_access https://graph.microsoft.com/user.read https://graph.microsoft.com/mail.readwrite https://outlook.office365.com/imap.accessasuser.all https://outlook.office365.com/smtp.send is not valid.\r\nTrace ID: c3282396-6231-4e11-8300-77bc2ca57f00\r\nCorrelation ID: 5f5145bf-7114-4e6c-ab11-30e7ff84a056\r\nTimestamp: 2020-05-06 08:08:48Z",
    "error_codes": [
        28000
    ],
    "timestamp": "2020-05-06 08:08:48Z",
    "trace_id": "c3282396-6231-4e11-8300-77bc2ca57f00",
    "correlation_id": "5f5145bf-7114-4e6c-ab11-30e7ff84a056"
}

当尝试使用microsoft graph的所有作用域时(从Azure Portal复制)

public static final List<String> SCOPES = Arrays.asList(
    "https%3A%2F%2Fgraph.microsoft.com%2Foffline_access",
    "https%3A%2F%2Fgraph.microsoft.com%2FUser.Read",
    "https%3A%2F%2Fgraph.microsoft.com%2FMail.ReadWrite",
    "https%3A%2F%2Fgraph.microsoft.com%2FIMAP.AccessAsUser.All",
    "https%3A%2F%2Fgraph.microsoft.com%2FSMTP.Send"
);

返回以下令牌(如果没有刷新令牌,则已请求offline_access)

{
    "token_type": "Bearer",
    "scope": "profile openid email https://graph.microsoft.com/IMAP.AccessAsUser.All https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/SMTP.Send https://graph.microsoft.com/User.Read",
    "expires_in": 3599,
    "ext_expires_in": 3599,
    "access_token": "eyJ0eXAiOiJKV1..."
}

没有成功:

A1 NO AUTHENTICATE failed.
{
    "error": "invalid_grant",
    "error_description": "AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.\r\nTrace ID: 09fc80f4-f5fd-4e52-938f-d56b71dd0900\r\nCorrelation ID: 4f35e05c-23c8-4fdc-a5a7-2fcde5a73b44\r\nTimestamp: 2020-05-08 12:13:30Z",
    "error_codes": [
        54005
    ],
    "timestamp": "2020-05-08 12:13:30Z",
    "trace_id": "09fc80f4-f5fd-4e52-938f-d56b71dd0900",
    "correlation_id": "4f35e05c-23c8-4fdc-a5a7-2fcde5a73b44"
}

因此,不,我需要使用两个独立的令牌,这取决于我需要管理的资源。

更新5:

如果它仍然不起作用-检查您的组织是否启用了安全默认值-他们禁用帐户的pop/imap/smtp auth-https://techcommunity.microsoft.com/t5/exchange-team-blog/announcing-oauth-2-0-support-for-imap-and-smtp-auth-protocols-in/bc-p/1544725/highlight/true#m28589


共有1个答案

杜河
2023-03-14

IMAP、SMTP作用域的目标是Exchange资源,而不是图形。而user.read和mail.readwrite是用于图形资源的。

我们不支持生成用于两个资源的令牌。因此,错误“为输入参数范围提供的值无效,因为它包含多个资源”。

您应该通过两次调用/token来分别生成两个令牌。1.为Exchange资源生成的IMAP、SMTP作用域。2.另一个具有图形作用域(user.read、mail.readwrite),用于图形资源。

 类似资料:
  • Office 365 online和OAuth2面临连接问题。0我已设置应用程序权限以及IMAP和SMTP连接。基本身份验证似乎可以正常工作。我相信IMAP已启用。我的应用程序被配置为任何组织目录(任何Azure AD目录-Multitenant)中的帐户,并使用授权类型的授权代码。 以及授权的Microsoft Graph范围https://graph.microsoft.com/IMAP.Ac

  • 我正在尝试使用smtplib在python 2.7中发送邮件。下面的代码非常简单: 现在当我执行下面的代码时,我不断得到这个异常:

  • 我正在使用私有电子邮件SMTP服务器向用户发送密码重置。他们的网站指示使用端口465,并在NodeEmailer中将安全设置为true。我似乎连接良好,但我无法验证。我已经仔细检查了我的用户名和密码,因此我知道问题出在我的NodeEmailer配置上: 有什么想法吗?

  • 我有一个客户端服务器场景。 我有厚客户端和瘦客户端(浏览器),它们与我的服务器进行通信。 我的胖客户端使用X-509系统证书进行客户端证书身份验证,并与服务器通信 此外,此证书用于生成签名URL(带过期时间),以便我的瘦客户机与服务器通信,用于完整性和授权目的。在这种情况下,我也有一个基于令牌的方法用于身份验证。 现在,我想使用客户端凭据或基于身份验证代码将身份验证机制移动到基于OAuth的流。

  • Tweepy API请求twitter return me Twitter错误响应:状态代码=401。 这是我的实际代码: 我曾试图用tweepy软件包删除推文,并获得了所有必需的密钥。镊子包装不起作用吗?有人能帮我解决这个问题吗。