I try to write a Java application that access an Exchange Web Services in order to read emails. Thus, I use the Exchange Web Services (EWS
) Java API provided by Microsoft.
I already had several issues with it, and I finally found that the authentication should be done using LDAP. Unfortunately, I'm not sure how to do such a thing. Does the EWS API allows to configure the authentication scheme to be used when connecting to the Exchange server ? If yes, how to configure that?
This is the code I use for connection, but it uses the default authentication scheme, i.e. NTLM
:
String url = "https//my-server/EWS/exchange.asmx";
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.setTraceEnabled(true);
service.setCredentials(new WebCredentials("user", "password"));
service.setUrl(url.toURI());
Mailbox mailbox = new Mailbox("foo@bar.com");
FolderId folder = new FolderId(WellKnownFolderName.Inbox, mailbox);
ItemView view = new ItemView(10);
view.getOrderBy().add(ItemSchema.DateTimeReceived, SortDirection.Descending);
FindItemsResults<Item> items = service.findItems(folder, view);
We resolved this issue. In fact, we had 2 solutions for that:
In the Microsft EWS API, the class NTLM
was wrong. So we re-built the JAR with the following code for the class:
private class NTLM {
/** Character encoding */
public static final String DEFAULT_CHARSET = "ASCII";
/**
* The character was used by 3.x's NTLM to encode the username and
* password. Apparently, this is not needed in when passing username,
* password from NTCredentials to the JCIFS library
*/
private String credentialCharset = DEFAULT_CHARSET;
void setCredentialCharset(String credentialCharset) {
this.credentialCharset = credentialCharset;
}
private static final int TYPE_1_FLAGS = NtlmFlags.NTLMSSP_NEGOTIATE_NTLM
| NtlmFlags.NTLMSSP_NEGOTIATE_UNICODE
| NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2;
private String generateType1Msg(String host, String domain) {
jcifs.ntlmssp.Type1Message t1m = new jcifs.ntlmssp.Type1Message(
TYPE_1_FLAGS, domain, host);
return jcifs.util.Base64.encode(t1m.toByteArray());
}
private String generateType3Msg(String username, String password,
String host, String domain, String challenge) {
jcifs.ntlmssp.Type2Message t2m;
try {
t2m = new jcifs.ntlmssp.Type2Message(
jcifs.util.Base64.decode(challenge));
} catch (IOException e) {
throw new RuntimeException("Invalid Type2 message", e);
}
final int type2Flags = t2m.getFlags();
final int type3Flags = type2Flags
& (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
jcifs.ntlmssp.Type3Message t3m = new jcifs.ntlmssp.Type3Message(
t2m, password, domain, username, host, type3Flags);
return jcifs.util.Base64.encode(t3m.toByteArray());
}
}
Another solution is to use the JWebServices library (commercial).
We had the same issue and although changing the NTLM class (as romaintaz suggested) works, it was breaking at some other point.
However, there is a newer version of the EWS Java library, hostet at github:
https://github.com/OfficeDev/ews-java-api
It now uses apache httpclient 4.4.1, which has a good NTLM-implementation.
Using this library, we had no more issues regarding NTLM authentication so far.