Wednesday, June 2, 2010

Oracle Access Manager and Kerberos (/Integrated Windows Authentication) with fallback to HTML forms

Back in January I posted an answer to the question:


In that post, as in the past I've always pointed people in the Right Direction and let them fill in the blanks themselves. This week I had to actually go get it working and given all the effort it took me I have a sneaking suspicion that most people listen to my suggested solution, nodded, said they understood and then skipped the Kerberos bit altogether.

First the requirements:
  • a Windows domain
  • a server in the domain with an IIS web server and a Web Gate installed/configured
  • a workstation in the domain (call this one workstation1)
  • workstation NOT in the domain (call this one workstation2)
What we want is for a user logged into workstation1 with their domain credentials to be able get into OAM-protected resources by going right to them via a bookmark, typing in a URL, clicking on an emailed or IM'd link or any other way they want. A user on workstation2 going to the same URL on the same web server should see OAM's HTML login form.

Seems simple, right? It's not.

The way IWA works is through the HTTP authentication method called Negotiate documented in RFC 4559. Basically your client says "GET /foo" and the server says "401. Gimme a Kerberos token" and optionally some text or HTML. Your browser repeats the first request and includes a Keberos token. The spec includes details of what the flow looks like on the wire.

In the olden days if your browser didn't know how to handle the Negotiate authentication method it would just show the HTML page that the web server sent back. Things have changed though - browsers tend to hide the real HTTP error pages and instead show "friendly" error pages. I also discovered that IE, at least in my test environment, pops a login box up on the screen to collect the credentials.

So what we need is a way to silently detect whether the web browser can authenticate to the web server or not. Once we have that putting together the OAM bits is just a matter of following the normal steps.

What didn't work...

I tried a bunch of ways to do that detection before finding one that worked. I am listing them here not to torture you, but to describe why they didn't work to save you the time and trouble of testing them out on your own.

Ways that didn't work:
  1. using IIS' 401 error page
  2. using XmlHttpRequest and XDomainRequest
  3. using Flash
As I mentioned above the 401 error page didn't work because IE pops up a basic-style box and hides the error page sent by the server. In fact that's the same solution I posted back in January... and it's wrong. Or at least it's wrong for IE 8.

XmlHttpRequest is the standard way that AJAX web apps make HTTP requests to the server via JavaScript. XDomainRequest is an IE 8+ proprietary extension that's basically the same thing as XmlHttpRequest but has different security restrictions; more info can be found on MS' site. Both of these exhibited the same behavior as the browser itself, exactly as the W3C spec says they should.

I tried Flash because it's almost always available on platforms that would support Kerberos and because it plugs into the browser and is initialized on browser startup. Unfortunately the URLRequest object in Flash doesn't provide low enough level control to avoid the pop-up box.

What DID work?
The only thing I could get to actually work without breaking my requirements was a Java Applet.

If you let it Java's URLConnection class handles the Kerberos authentication for you. All you need to do is wrap a try/catch block around the call and fire it off. If you get back content then the HTTP transaction succeeded. This is what the Applet's code looks like:
 URL url = new URL("http://testmachine.testdomain.com/IWAProtected/");
URLConnection urlConn = url.openConnection();

urlConn.setAllowUserInteraction(false);
urlConn.setUseCaches(false);

DataInputStream dis = new DataInputStream(urlConn.getInputStream());
data = new String();

String s;
while ((s = dis.readLine()) != null) {
System.out.println("Read data" + s);
data += s + "\n";
}
dis.close();
Make /IWAProtected/ protected by IIS' Integrated Windows Authentication, put that code into an Applet and add the Applet to an HTML page elsewhere on your site and you'll be able to tell whether the user is logged into the domain or not. tag on your page and

Pulling the bits together
Once you have an applet that can detect that the user is logged into the domain all that remains is to put the pieces together. There are a bunch of ways to get across the finish line depending on how you want it to work, the simplest of which is to make an HTML login page your "default". You add the applet to that page, let the applet detect that IWA is available to the user. If the applet determines that IWA isn't going to work for the user they just fill out the normal HTML form and log in. If the applet determines that IWA will work for the user you use JavaScript to kick the user into the Kerberos authentication process.

I'll leave some of the details up to you, but those are the broad strokes.

Hope this helps!

3 comments:

  1. I tried this approach out and ran into a few issues -

    1) I'm using JRE 1.6.0_20, and the "urlConn.setAllowUserInteraction(false);" part just seems to be disregarded. On a machine where I am not logged on to the corporate domain, the JRE throws up an authentication dialog!

    2) Also, if I turn off the IWA capability in my browser (when logged on to the domain), the applet still reports that IWA will work for me. Based on this, if I kick off the Kerberos authentication process, the browser will just try to collect credentials via the basic popup.

    Any thoughts?

    ReplyDelete
  2. otrams.. i'm having the same issue with #1 where the authentication dialog keeps popping up regarless of "urlConn.setAllowUserInteraction(false);"

    Any solution found?

    ReplyDelete
  3. If the Java Applet finds that it can do the transaction then the machine must be in the domain (or something magical is happening!). Short of having the applet change IE's config setting you can't really help that the user has twiddled the checkbox. And to do THAT you'd have to sign the applet, so the user would wind up getting a dialog box anyway.

    So sadly I don't think there's a perfect answer.

    ReplyDelete

Note: Only a member of this blog may post a comment.