Servlet

In a nutshell I am trying to create a single-signon environment which will encompass mutiple intra-net sites. Each site uses its own security model, but all use session cookies to "maintain state".

I have tried to implement this using HttpURLConnection calls. I have the user authenticate against LDAP and then automatically log them into any appropriate sites using the HttpURLConnection.getOutputStream to write the logon information to the appropriate logon page and HttpURLConnection.getInputStream to read the responses back from those logon pages.

The cookies get returned to my servlet and then my servlet adds them to the response it builds (changing the domain and path attributes to be "intra-net domain"-wide.

Everything works fine up to this point; all session cookies are retreived and forwarded to the initial client. However, when that client (the users browser) requests a page on one of these other sites the session is not recognized.

Please, does anyone have any idea why and/or how I can get around this? Below is the main portion of the code I am using to retrieve/set the session cookies. Thanks in advance.

--

public void doGet(HttpServletRequest req, HttpServletResponse res)

throws ServletException, IOException {

/*

** Prepare the response.

*/

res.setContentType("text/html");

PrintWriter out = res.getWriter();

out.println("<PRE>");

/*

** Prepare connection to remote logon page.

*/

URL logonPage = null;

String url = "the logon page.jsp"; //fully qualified

logonPage = new URL(url);

String argString = "Logon=data&Url=encoded";

HttpURLConnection con = (HttpURLConnection)logonPage.openConnection();

con.setUseCaches(false);

con.setRequestMethod("POST");

con.setInstanceFollowRedirects(true);

con.setDoInput(true);

con.setDoOutput(true);

/*

** Work around a Netscape bug...

*/

con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

/*

** Send logon data to remote url.

*/

DataOutputStream dataStream = new DataOutputStream(con.getOutputStream());

dataStream.writeBytes( "\n" + "\n" + argString);

dataStream.flush();

dataStream.close();

/*

** Retrieve and parse the remote response.

*/

InputStream in = con.getInputStream();

for (int i=1; con.getHeaderField(i) != null; i++)

{

out.println("Key : " + con.getHeaderFieldKey(i));

out.println("Field : " + con.getHeaderField(i));

if (con.getHeaderFieldKey(i).equalsIgnoreCase("set-cookie"))

{

String cookieField = con.getHeaderField(i);

int keyValPos = cookieField.indexOf(";");

String cookieKeyVal = cookieField.substring(0,keyValPos);

int pos = cookieKeyVal.indexOf("=");

String cookieAttrName = cookieKeyVal.substring(0, pos);

String cookieAttrValue = cookieKeyVal.substring(pos+1);

out.println("CookieAtrrName : " + cookieAttrName);

out.println("CookieAtrrValue : " + cookieAttrValue);

Cookie creds = new Cookie(cookieAttrName, cookieAttrValue);

creds.setPath("/");

creds.setDomain(".mydomain.com");

res.addCookie(creds);

}

}

out.println("</PRE>");

}

[3364 byte] By [steveEbersole] at [2007-9-26 3:08:05]
# 1

Let me clarify when I say the session is not recognized:

The session cookie value (cookie named jsessionid) exactly matches the value of request.getSession().getId(). But for some reason, data stored as part the session created initially (specifically a bean with session scope) is not available later.

steveEbersole at 2007-6-29 11:12:32 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2

You are having your special servlet(which I beleive is also the one accessing credentials from the LDAP server) create HTTP session on the remote application. Right ?

How are you making sure that this artificially(using HTTPURLConnection) created session is the same(i.e has the same ID) as the one created freshly by the borwser later when it accesses that remote application by itself ?

I am myself working on the initial design of an enterprise-wide single signon scheme/architecture. And would like to exchange ideas with you.

neville_sequeira at 2007-6-29 11:12:32 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3

In my setup, it doesn't actually create any sessions on its own. It simply requests sessions from the appropriate server/login page and then passes the session created by the page back to the client. In theory it works this way (referencing the code-snipets from above):

where mySerlvet is the name of my signon servlet;

and login.jsp is logon page for a particular web app

The variable urlLoginPage represents an object to the login.jsp. Opening an HttpURLConnection to the urlLoginPage allows both output to be written the the login page (for passing the "form" data) and input to be read from the logon page (supposedly after successful login). When reading back the response from login.jsp, the headers in its response would contain a key of "set-cookie" for any cookies it is trying to set on the client (in this case myServlet is really just the client). The following code snippet simply reads the cookies being set in the response from login.jsp and transfers them to the response from myServlet:

for (int i=1; con.getHeaderField(i) != null; i++)

{

if (con.getHeaderFieldKey(i).equalsIgnoreCase("set-cookie"))

{

String cookieField = con.getHeaderField(i);

int keyValPos = cookieField.indexOf(";");

String cookieKeyVal = cookieField.substring(0,keyValPos);

int pos = cookieKeyVal.indexOf("=");

String cookieAttrName = cookieKeyVal.substring(0, pos);

String cookieAttrValue = cookieKeyVal.substring(pos+1);

Cookie creds = new Cookie(cookieAttrName, cookieAttrValue);

creds.setPath("/");

creds.setDomain(".myDomain.com");

res.addCookie(creds);

}

}

In essence, myServlet simply acts as a passthrough between the user's browser and the multiple web apps for which we are handling logon.

steveEbersole at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4

I understood the general idea.

But, what I did not understand is...

Lets say the pass-through servlet is called passThrough and one of the application for which passThrough handles logon is called A_app.

Then, when passThrough accesses the logon page of A_app, how does it make sure that the session cookie it receives from successful logon at A_app and which is subsequently send to user's browser, does indeed go back to A_app when the user's browser accesses A_app directly at a later time.

I guess, a simpler way to ask the same question is...

According to the Cookie specifications, cookies cannot go accross domain boundaries. And also, according to the Cookie specifications, browser automatically refuses cookies that have their domain different from the domain of the server which created them.

Then how did you manage to do what you are doing ?

neville_sequeira at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5

Most of the appss I am dealing with are intranet apps, and all are on our company domain.

>> According to the Cookie specifications, cookies cannot go accross domain boundaries. Yes, they cannot cross network domain boundaries. They can however be made less specific. For example lets say my login.jsp page resides at http://server1.myDomain.com/start/login.jsp

my myServlet page resides at http://server2.myDomain.com/servlet/HttpLoginHandler

The default domain (i.e., accessibility) for cookies if none is specified is server-level (server1.myDomain.com and server2.myDomain.com). However, you can make cookie domains less-specific within the same network domain. That is I can set a cookie generated on server1.myDomain.com to have a domain of myDomain.com (because it is getting less specific), but not to server2.myDomain.com and definitely not yourDomain.com.

Because we are dealing with mostly intranet sites and also because these are session cookies (i.e., generally pretty small) I am overriding the server-level default and just setting these to myDomain.com

So, again as an example, say I previously set two cookies (name=session1cookie;domain=myDomain.com) and (name=session2cookie;domain=server1.myDomain.com). Now when the browser requests a URL/resource from server1.myDomain.com, both cookies will be sent. When requesting from server2.myDomain.com only session1cookie will be sent. And obviously when "hitting" yourServer.yourDomain.com neither will be sent.

There is a practical limit to the size of data that can be sent in cookies (I think its like 1-2 Mb total). But if you will be under that limit, then the easiest way is to 1) set the domain as least-specific as possible and 2) set the path to root (path=/). However, then everything goes everywhere and conceivably you could run into "cookie-name-clash". For example the test I am trying in the code above hits a JRun server and JRun always uses jsessionid as the name of its HttpSession session cookies; thus servers could possibly be over-writing each others cookies.

I haven't really come up with a real graceful or easily-implemented way around this yet.

My email is steberso@vignette.com if you want to talk some more about this. Maybe we could bounce some ideas off each other.

steveEbersole at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 6

Also, I don't have the luxury (as I am sure many do not) of having all of the web apps being JSP/Servlet. If you are lucky enough to be in such a situation then EJB would be a really great solution for this. You could simply have the servlet authenticate against LDAP and then have it instantiate the EJB storing the authentication data for the various apps into the bean with your own session id as PK (and setting the PK as a cookie in the response to the browser). Each of the web apps could then check for this cookie and if present grab its authentication details from the bean.

Ahhhh, if only....

steveEbersole at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 7

< If you are lucky ...

No man, I am actually trying to come up with a scheme that will work ACROSS DOMAINS.

and so...

< Ahhhh, if only....

Ahhhhhhhhhhhhhhhhhhh

Can you point me to any material on the web or otherwise that you might have hit upon and found to be useful in your endevour ?

p.s. I wonder on what basis products like (Siteminder + Affiliate agent) from Netegrity claim that they support cross-doamin cookies !

neville_sequeira at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 8
...and also, no EJBs allowed in our design.
neville_sequeira at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 9

Hi steveEbersole,

So that the actual target application can create the session ID and the corresponding cookie appropriately, what sort of information about the end user's browser does your passThrough servlet gather and then forward on the URLConnection to the target application ?

neville_sequeira at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 10

I am not familiar with Affiliate nor Siteminder, so I am not really sure about their claims that you mention.

I have not found any online resources on this topic. Really I have found no resources dealing specifically with what we are attempting to do.

There is a little bit more to the code than the snippet I pasted in my original query. For this point, my servlet loops through all of the headers it is sent (which contain the USER_AGENT information from the original requesting browser) and sets these in its request headers to the logon page.

steveEbersole at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 11

Hey neville, I found my problem if you are still interested.

Really simple and stupid (as it always seems to be with these "big" issues). The problem is the two extra newlines I place in front the the variable argString which is written to the HttpURLConnection's output stream.

I was think of the 2 newlines required between the headers and the body, but apparently this class handles it automatically for you. I removed the "\n" + "\n" + from the println arg list and all worked fine.

steveEbersole at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 12

I have been through frustrations of those kinds before myself. I know how it feels when you resole it ultimately.

I wish there was a way for one to award duke dollars to oneself !

However, right from the time you posted your original issue, I have always wondered...

What about the artificially created session session timing out before the client browser accesses the actual business application ? Then the client browser will get a cookie that is different from the artificially create one. Right ?

neville_sequeira at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 13

Sorry, haven't been out here for a while.

I know we went through this before, but just to make sure we're on the same page with the wording: there are no "artificially created sessions"; my servlet is not actually creating any sessions or session cookies itself. It is merely asking another resource (the business app's login page) to create a new session on behalf of the client (browser) and returning to the client any session details (mainly the session cookies) returned by the remote resource.

That being said, yes there is definitely the possibility of a session for a particular business app timing out after this initial login. There are a couple of ways I had thought to handle this. Probably the most promising was to do the following:

1) Identify a "driving" or "master" session. There are a couple of ways to look at this. For example, in my setup, we have a particular site which already authenticates against LDAP. Furthermore, its login processing has an optional parameter (in the HTML form data) which allows you to specify where "control" should be sent after its processing (it just sends a simple redirect back to the browser with this parameter as the target). I utilize this login, specifying my servlet as the page to which to redirect control. (Really its just _A_ cookie that we are interested in, and I decided to use the cookies returned by this process as it is unique and already represents a session).

2) Here you would have to make slight modifications to the login pages of the remaining buiness apps (not ideal, i know...). In our intranet (as in most), the business app's actual pages check the validity of a user's session and if not valid, redirect the browser to its login page. This is good as it gives me an opportunity to centralize and limit these required changes to each app's login page. In the processing of the login, first check for the presence of the "master" session cookie. If it is present, then simply authenticate or re-authenticate the person based on the data present in the "master" cookie. Of course, this makes the assumption that your intranet is considered secure enough to allow you to store this type of data in a session cookie (we create the cookie values with strong encryption).

There were some others, but most involved EJB and/or JavaBeans both of which you had mentioned you are unable to utilize. And plus the one outlined above required the least amount of reworking/new-coding to the existing application authentication structures.

steveEbersole at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 14
First of all, welcome back !Secondly, thanks for the clarifying again.And thirdly, this now sounds similar to the solution we are implementing !!!Or is it in the nature of the problem ?
neville_sequeira at 2007-6-29 11:12:33 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 15
Sorry, I'm a designer... I just feel an overwhelming urge to clarify everything. ;o)I think its just the nature of the issue we are dealing with. Outside of EJB and/or CORBA, there is really not a "clean" way of dealing with this.
steveEbersole at 2007-7-1 3:21:56 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...