Consuming Web Services with logged in user credentials (double hop)

Mar 18, 2011 at 11:02 AM

My scenario: I'm using Waffle's NegotiateSecurityFilter for SSO on Apache Tomcat to authenticate users for my web app. Now my application wants to consume the Microsoft Exchange Web Services (EWS) impersonating the logged in user from java. The calls to Exchange Web Services should be with the windows user credentials of the logged in user, so e.g. if the webapp creates an appointment it will be in the mailbox of the logged in user. To consume the Exchange Web Services via SOAP I'm using JAX-WS (Metro) http://jax-ws.java.net/ . Calling the EWS with the service account of Apache Tomcat works, but now I want to impersonate the logged in user.

As far as I understand the protocols I'm facing a "double hop" problem (or "two hop") and have to use Kerberos and the web server has to be trusted for delegation. NTLM is not possible, because it can't delegate the credentials by design (client -> web-server / web-server -> EWS). So the "NegotiateSecurityFilterProvider/protocols" is "Negotiate".

My first try was to activate the new impersonation feature in Waffle 1.4 and hoped, that this would be enough to call the EWS with the logged in users credential. A problem is, that JAX-WS (Metro) uses the java.net.Authenticator for the credentials, and the Authenticator seems to be static and only initialized at at the first call. 

Another try was to use the Java EWS API from Microsoft http://archive.msdn.microsoft.com/ewsjavaapi It uses the HttpClient 3.1 and JCIFS 1.3.15 for the Web Services calls but I think HtppClient 3.1 doesn't supports Kerberos.

I know this is not the right place to ask how to consume EWS but maybe someone can point me in the right direction.

  • Is my theory correct, that it should be possible to make Web Service calls with the logged in user, or is this technically not possible with Waffle's impersonation?
  • Is there a way around the static Authenticator problem when using JAX-WS (Metro) with Kerberos? (Basic Authentication would work, but I don't have the users password).
  • Any other ideas how to consume a SOAP Webservice from Microsoft using the logged in user credentials?

So, I'm clutching at straws, but maybe someone has some hints.

Developer
Mar 18, 2011 at 6:15 PM

I'm not that familiar with EWS. Does it support logging in using kerberos?

I could be wrong, but looking at the java.net.Authenticator class, it seems usefull only for getting a PasswordAuthentication object. I think the Authenticator is just a way to set the username and password for every client without explicitly setting it on every client like this:

port.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, usename);
port.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);

If this is the case, the Autheticator isn't going to help you out much. When you use Waffle for single sign on, you do not get the users username and password.

If you EWS does support kerberos authentication, you'll probably have to use JAAS+GSSAIP to handle kerberos login from Java. I've never tried using Waffle and GSSAPI together, so I'm not sure if they play nicely together. I have a feeling that they will not, but its something I'll have to try to know for sure.

Have you considerd using Exchange Impersonation?

http://msdn.microsoft.com/en-us/library/bb204088.aspx

Mar 18, 2011 at 7:34 PM

Thanks for your answer.

Yes, EWS supports kerberos. It's behind a virtual directory on IIS which is configured to authenticate with windows authentication.

My idea behind the Authenticator was, that it is automatically initialized with the credentials of the Apache Tomcat service account if you don't explicit set credentials when calling the web services. So, for every call I want to say "just use the credentials of the impersonated SSO user". But I'm afraid it isn't designed for that and it seems that it can't be replaced once it's initialized.

I haven't read anything about GSSAPI so far, so I'll look into it.

Yes, I've considered using Exchange Impersonation. As a matter of fact, my application already works with Exchange Impersonation, but sadly some IT departments don't like Exchange Impersonation, because it involves giving the Apache Tomcat service account Exchange Impersonation rights to the users mailboxes and they fear a security problem with this. They would be fine if the EWS call is initiated with the windows token of the logged in SSO user, so I'm searching for a way to achieve this.

Developer
Mar 22, 2011 at 7:06 PM

I've read a bit more about kerberos support in metro. It appears that metro supports kerberos authentication with message security, but not with transport security. EWS seems to use transport security. I think the best way to make this work is to provide a new client transport in metro that uses Waffle to do SPNego. Basically metro needs to behave as a browser would and handle WWW-Authenticate: Negotiate headers. I'm currently trying this approach out. I'll let you know if I get it working. If you are interested in experimenting with it yourself, have a look at

http://fisheye5.cenqua.com/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/api/pipe/TransportTubeFactory.java?hb=true

That explains how to configure a new transport in metro.

Mar 23, 2011 at 4:27 PM

Great, sounds promising. Thanks for the info.

Apr 7, 2011 at 9:07 AM

I just want to ask if you had the chance to gain some new insights?

Developer
Apr 13, 2011 at 7:29 PM

I've found that it might be a little easier than I thought. Metro uses HttpURLConnection to handle http requests. HttpURLConnection has the ability to handle Negotiate authentication. You just have to configure a Kerberos login module using JAAS. I tried it, but haven't got it to work yet. Here's the link for configuring a kerberos login module, maybe you'll have more luck than I have had. http://download.oracle.com/javase/6/docs/technotes/guides/security/jgss/lab/part6.html

I'll post again if I get it working.

Nov 4, 2011 at 8:43 PM

I am working the same problem. If I configure a Kerberos login module with JAAS, how is it going to get the credential of the user who authenticated to the application? Do I need to pass it? How is this accomplished?