Search code examples
javaldapexchangewebservicesewsjavaapi

How to use LDAP authentication for the Exchange Web Services connection in Java?


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);

Solution

  • 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).