我们正在尝试使用 OAUTH2 身份验证将 javamail (1.6) 客户端连接到托管在 Office365 上的 Office365 邮箱。
无论我们做什么,我们都会不断收到 A1 NO AUTHENTICATE failed。
我们已经注册了我们的应用程序
API权限
我们遵循了所有说明
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
我们的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>"
然后在我们的 java 代码中,我们将商店与从上述 HTTP POST 获取的访问令牌连接起来
store.connect(host, user, oauth2_access_token);
我们还尝试了这个 powershell 脚本,它返回相同的错误
https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1
我不认为该问题是 JavaMail 特有的。
确定访问令牌是否具有正确的权限或者是否存在其他阻止身份验证的因素非常困难
我们还能尝试什么?
Update 1
如果我们使用powershell脚本
https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1
仅传递客户端 ID 和redirectUri,脚本会提示我进行批准,并且成功
但如果我们使用 clientsecret 授权失败
Update 2
我可以成功地将 javamail 与 powershell 脚本生成的访问令牌一起使用。
显然,使用 clientsecret 创建的令牌没有足够的权限来访问 IMAP 或邮箱
我开始怀疑使用客户端密钥的令牌请求是否不起作用,因为我们的 Azure Active Directory 启用了“安全默认值”。
可能是强制执行了 MFA,因此任何非交互式请求都会被阻止
Update 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"
客户端凭证流中的第二个令牌具有属性“角色”,但没有范围
"roles": ["IMAP.AccessAsApp"]
解决!
查看访问令牌,我们注意到客户端凭据流主题 (sub) 是我们未设置的 ID。
这里有一个问题:在使用 powershell 在线交换创建服务主体时,对于 serviceid,您必须使用企业应用程序的 objectid。
新ServicePrincipal -AppId {clientid}-ServiceId {企业应用程序对象ID}-组织{tenantid}
创建应用程序注册 Azure AD 时,您还创建企业应用程序
应用程序对象 ID 与企业应用程序对象 ID 不同。
客户端凭证流使用企业应用程序对象 ID 作为请求授权的用户。
使用 powershell 授予对邮箱的访问权限也是如此
添加MailboxPermission -Identity {email} -User-ServiceId {企业应用程序对象ID}-访问权限FullAccess
不幸的是认证过程如此繁琐