无法使用 JavaMail 在 Office365 上对 IMAP 进行身份验证

Iva*_*zzi 11 imap jakarta-mail oauth-2.0 office365 azure-active-directory

我们正在尝试使用 OAUTH2 身份验证将 javamail (1.6) 客户端连接到托管在 Office365 上的 Office365 邮箱。

无论我们做什么,我们都会不断收到 A1 NO AUTHENTICATE failed。

我们已经注册了我们的应用程序

API权限

1

我们遵循了所有说明

https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth

包括运行 powershell 命令来使用应用程序 ID 和对象 ID 创建主体,并且我们授予应用程序对我们想要访问的电子邮件箱的完全访问权限。

对于身份验证,我们执行如下 HTTP POST,生成访问令牌

这是具有共享秘密的客户端凭据流,如下所述 https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow

https://login.microsoftonline.com/ {我们的租户 id}/oauth2/v2.0/token

client_id=...
client_secret=...
grant_type=client_credentials
scope=https://outlook.office365.com/.default
Run Code Online (Sandbox Code Playgroud)

我们的javamail配置

mail.store.protocol="imap"
mail.imap.host="outlook.office365.com"
mail.imap.port="993"
mail.imap.ssl.enable="true"
mail.imap.starttls.enable="true"
mail.imap.auth="true"
mail.imap.auth.mechanisms="XOAUTH2"
mail.imap.user="<email box>"
Run Code Online (Sandbox Code Playgroud)

然后在我们的 java 代码中,我们将商店与从上述 HTTP POST 获取的访问令牌连接起来

store.connect(host, user, oauth2_access_token);
Run Code Online (Sandbox Code Playgroud)

我们还尝试了这个 powershell 脚本,它返回相同的错误

https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1

我不认为该问题是 JavaMail 特有的。

确定访问令牌是否具有正确的权限或是否存在其他阻止身份验证的因素非常困难

我们还能尝试什么?

更新1

如果我们使用powershell脚本

https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1

仅传递客户端 ID 和redirectUri 脚本会提示我批准并且成功

但如果我们使用 clientsecret 授权失败

更新2

我可以成功地将 javamail 与 powershell 脚本生成的访问令牌一起使用。

显然,使用 clientsecret 创建的令牌没有足够的权限来访问 IMAP 或邮箱

我开始怀疑使用客户端密钥的令牌请求是否不起作用,因为我们的 Azure Active Directory 启用了“安全默认值”。

可能是强制执行了 MFA,因此任何非交互式请求都会被阻止

更新3

https://jwt.ms允许解码访问令牌

仅使用 clientid(代码授予流程)创建的令牌与使用 client_secret(客户端凭据流程)创建的令牌非常不同。

在“代码授予交互”的令牌中,有一个名为“scp”范围集的属性,它列出了范围,无论我在客户端应用程序 API 权限中拥有什么???

"scp": "IMAP.AccessAsUser.All Mail.Read Mail.Read.All Mail.Read.Shared Mail.ReadBasic User.Read"
Run Code Online (Sandbox Code Playgroud)

客户端凭证流中的第二个令牌具有属性“角色”,但没有范围

"roles": ["IMAP.AccessAsApp"]
Run Code Online (Sandbox Code Playgroud)

解决!

查看访问令牌,我们注意到客户端凭证流主题 (sub) 是我们未设置的 ID。

这里有一个问题:在在线交换中使用 powershell 创建服务主体时,对于 serviceid,您必须使用企业应用程序的 objectid。

New-ServicePrincipal -AppId {clientid} -ServiceId {企业应用程序对象id} -组织 {tenantid}

创建应用程序注册 Azure AD 时,您还创建企业应用程序

应用程序对象 ID 与企业应用程序对象 ID 不同。

客户端凭证流使用企业应用程序对象 ID 作为请求授权的用户。

使用 powershell 授予对邮箱的访问权限也是如此

Add-MailboxPermission -Identity {电子邮件} -User -ServiceId {企业应用程序对象ID} -AccessRights FullAccess

不幸的是认证过程如此繁琐

小智 0

我的两分钱,如果您仍然面临 javamail 尝试连接到邮箱和阅读电子邮件的身份验证失败,首先确保 azure Active Directory 中的应用程序设置具有以下权限。

IMAP.AccessAsApp

邮件阅读

Mail.Send(用于发送)

其次,使用原帖子中提到的企业应用程序 ID创建服务主体。完成后,在此处检查您生成的令牌是否具有您分配的所有角色。

即使您分配了必要的角色并且可以通过 powershell 连接到邮箱,您仍然可能会从 javamail 获得身份验证失败,因为您可能错误地使用了此属性 (mail.imap.auth.mechanisms),请将 mail.imap 替换为 mail.imaps它应该可以解决问题。

"mail.imaps.auth.mechanisms"="XOAUTH2"
"mail.imap.host"="outlookoffice365.com"
"mail.smtp.port"=993
"mail.store.protocol"="imaps"

session.getStore("imaps")
store.connect(host,port,user,token)
Run Code Online (Sandbox Code Playgroud)

祝你好运 !!