[英]Authentication Failure for IMAP using Client Credential flow for OAuth2.0 | Java | Exchange Online
我在尝试使用OAuth2.0的客户端凭据授予流连接两个 IMAP 协议时遇到身份验证失败问题。 在哪里,我一直按照微软在其分步指南中建议的步骤进行操作,即“ 使用 OAuth 验证 IMAP、POP 或 SMTP 连接”
我一直在使用这个 github 项目使用客户端凭据授予流程获取访问令牌: MSAL Client Credential Grant using Java
Java IMAP代码
public static void connectIMAP(String userEmail, String accessToken){
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props= new Properties();
props.put("mail.imap.ssl.enable", "true");
props.put("mail.imap.sasl.enable", "true");
props.put("mail.imap.port", "993");
props.put("mail.imap.auth.mechanisms", "XOAUTH2");
props.put("mail.imap.sasl.mechanisms", "XOAUTH2");
props.put("mail.imap.auth.login.disable", "true");
props.put("mail.imap.auth.plain.disable", "true");
props.setProperty("mail.imap.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imap.socketFactory.fallback", "false");
props.setProperty("mail.imap.socketFactory.port", "993");
props.setProperty("mail.imap.starttls.enable", "true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true);
try {
final Store store = session.getStore("imap");
store.connect("outlook.office365.com",userEmail, accessToken);
} catch (NoSuchProviderException e) { // session.getStore()
e.printStackTrace();
} catch (MessagingException e) { // store.connect()
e.printStackTrace();
}
}
以下是我在使用 MSAL 库执行客户端凭据授予流程时使用的凭据
[注意:我一直在使用默认 Active Directory,以及我的 Azure 帐户的默认用户(管理员)。 这样好吗? 还是需要新的自定义 Azure AD 和单独的租户来执行客户端凭据流]
下图包含我在我的应用程序中应用的权限列表:应用权限列表的图像
错误日志:
*** IMAP ***
DEBUG: JavaMail version 1.5.6
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: setDebug: JavaMail version 1.5.6
DEBUG: getProvider() returning javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle]
DEBUG IMAP: mail.imap.fetchsize: 16384
DEBUG IMAP: mail.imap.ignorebodystructuresize: false
DEBUG IMAP: mail.imap.statuscachetimeout: 1000
DEBUG IMAP: mail.imap.appendbuffersize: -1
DEBUG IMAP: mail.imap.minidletime: 10
DEBUG IMAP: enable STARTTLS
DEBUG IMAP: enable SASL
DEBUG IMAP: SASL mechanisms allowed: XOAUTH2
DEBUG IMAP: closeFoldersOnStoreFailure
DEBUG IMAP: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [UABO......]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAP: AUTH: PLAIN
DEBUG IMAP: AUTH: XOAUTH2
DEBUG IMAP: protocolConnect login, host=outlook.office365.com, user=ManishPrajapati@SampleOrg2022.onmicrosoft.com, password=<non-null>
DEBUG IMAP: SASL Mechanisms:
DEBUG IMAP: XOAUTH2
DEBUG IMAP:
DEBUG IMAP: SASL client XOAUTH2
DEBUG IMAP: SASL callback length: 2
DEBUG IMAP: SASL callback 0: javax.security.auth.callback.NameCallback@73f9ac
DEBUG IMAP: SASL callback 1: javax.security.auth.callback.PasswordCallback@1064425
A1 AUTHENTICATE XOAUTH2 dXNlcj.....
A1 NO AUTHENTICATE failed.
javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:725)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at test.ClientCredentialGrantAndConnect.connectIMAP(ClientCredentialGrantAndConnect.java:166)
at test.ClientCredentialGrantAndConnect.main(ClientCredentialGrantAndConnect.java:45)
任何解决问题的帮助将不胜感激。
谢谢你。
我现在可以在交换在线服务器上为 IMAP 协议执行 OAuth2.0 身份验证。 我发现我的方法的问题在于,由于缺乏使用 Azure 的经验,我从错误的地方使用了一些参数。
按照分步指南中给出的说明并设置新创建的应用程序的权限就可以了。 但真正的问题是本文末尾给出的查询,我们需要运行 3 个命令才能执行 OAuth2.0
据我了解,以下是执行服务主体相关查询时使用的参数列表:
使用的参数(以及在哪里找到它们):
命令:
我面临的困惑:
我能够使用客户端凭据授予生成的 IMAP OAuth2 访问令牌连接到邮箱。 以下是详细信息:
Java 代码(将以下代码中的 clientid、secret、authority 和 email id 替换为您的 azure 应用注册中的值)
//this method returns the token
public String getAccessTokenByClientCredentialGrant() {
String accessToken = null;
String clientId = "<client id from azure app registration>";
String secret = "<client secret from azure app registration>";
String authority = "https://login.microsoftonline.com/<tenant-id from azure>/oauth2/v2.0/token";
String scope = "https://outlook.office365.com/.default";
log.info("Client ID : "+clientId);
log.info("Client Secret : "+secret);
log.info("Auth Server: "+authority);
log.info("Scope: "+scope);
try {
ConfidentialClientApplication app = ConfidentialClientApplication.builder(
clientId,
ClientCredentialFactory.createFromSecret(secret))
.authority(authority)
.build();
// With client credentials flows the scope is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal), and then granted by a tenant administrator
ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
Collections.singleton(scope))
.build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
IAuthenticationResult result = future.get();
accessToken = result.accessToken();
} catch(Exception e) {
log.error("Exception in acquiring token: "+e.getMessage());
e.printStackTrace();
}
log.info("Access Token : "+accessToken);
return accessToken;
}
//This method connects to store using the access token
public Store connect(String userEmailId, String oauth2AccessToken) throws Exception {
String host = "outlook.office365.com";
String port = "993";
Store store = null;
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props= new Properties();
props.put("mail.imaps.ssl.enable", "true");
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.port", port);
props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put("mail.imaps.auth.login.disable", "true");
props.put("mail.imaps.auth.plain.disable", "true");
props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imaps.socketFactory.fallback", "false");
props.setProperty("mail.imaps.socketFactory.port", port);
props.setProperty("mail.imaps.starttls.enable", "true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true);
store = session.getStore("imaps");
log.info("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: "+ port
+ ", userEmailId: " + userEmailId+ ", AccessToken: " + oauth2AccessToken);
try {
store.connect(host, userEmailId, oauth2AccessToken);
log.info("IMAP connected with system properties to Host:" + host + ", Port: "+ port
+ ", userEmailId: " + userEmailId+ ", AccessToken: " + oauth2AccessToken);
if(store.isConnected()){
log.info("Connection Established using imap protocol successfully !");
}
} catch (Exception e) {
log.error("Store.Connect failed with the errror: "+e.getMessage());
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
log.error(exceptionAsString);
}
return store;
}
//the main method which calls the above 2 methods.
public void getEmailContents() throws Exception {
Store store = null;
String accessToken = getAccessTokenByClientCredentialGrant();
String emailId = "<email which needs to be read>";
try {
store = connect(emailId, accessToken );
} catch (Exception ex) {
log.error("Exception in connecting to email " + ex.getMessage());
ex.printStackTrace();
}
//write code to read email using javax.mail code
}
确保您的应用程序在 Azure 应用程序注册下注册,并且在应用程序的“API 权限”中授予以下 API 权限(应用程序权限)。
Office 365 在线交换
还要确保使用以下链接中的命令将邮箱链接到 Azure: https://docs.microsoft.com/en-us/graph/auth-limit-mailbox-access
Test-ApplicationAccessPolicy -Identity <email> -AppId <app id>
您还可以使用https://jwt.io/解码从 java 代码生成的访问令牌,并验证权限是否正确。
验证 office365 email 配置并确保 IMAP 已启用:可以在以下链接中找到帮助。 https://www.limilabs.com/blog/office365-enable-imap-pop3-smtp
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.