| By Abraham Kang, Donald Levy | Article Rating: |
|
| December 1, 2001 12:00 AM EST | Reads: |
19,142 |
Single sign-on is becoming an important issue for corporations and Java developers. Corporations require applications to be secure. Users demand applications to be easy to use. Usually, the more secure an application is, the more difficult it is to use. For example, users are inundated with remembering multiple logins to different systems.
Part 1 of this article (JDJ, Vol. 6, issue 11) provided readers with a conceptual understanding of single sign-on (SSO). In Part 2 we explain the programming and setup issues related to SSO for Web and standalone applications. With this knowledge, you'll be able to implement SSO solutions for your applications.
Balancing Security with Easy Usage
It was noted that more than 45% of calls to corporate help desks involve user ID or password-related issues. To avoid memorizing multiple logins users put their passwords in insecure locations (like their monitors).
SSO addresses these issues by creating a single-user ID and password that can access multiple applications.
Implementing SSO for Web Applications
Single sign-on for Web applications is a protocol between the client (browser), member server, and login server. The SSO protocol establishes a set of procedures for authentication. All of the SSO procedures utilize encryption to guarantee the confidentiality of data, redirection, and JavaScript to facilitate client communication between the member servers and login server, and cookies to store SSO information. To understand the SSO protocol, we first focus on SSO's components. The first component is encryption.
Encryption
Encryption is used to encrypt URL parameter and cookie values. Sample JCE code is available on the JDJ Web site (www.sys-con.com/java/sourcec.cfm). Using JCE encryption is straightforward, but make sure you convert raw ciphertext to hex before putting it into the cookie payload or setting it as a request parameter value. The URLEncoder an URLDecoder have problems encoding and decoding ciphertext. By converting the ciphertext to hex, you don't need to URLEncode data.
To facilitate hex encoding and pluggable encryption algorithms, you'll want to create a general encryption and decryption interface, then an abstract class that implements the interface with concrete facade subclasses that utilize different encryption algorithms. This allows you to provide the encryption and decryption services with the flexibility to plug in new algorithms in the future (see Figure 1 for UML's advantage).
Now that we've covered encryption, let's talk about redirection.
A redirect is a type of command sent from the server that sends a browser to another location. It sends users to different servers without the user's intervention. There are two ways of redirecting users in Java. The first is through the HttpServletResponse object's sendRedirect("fullURL"). The second sends HTML and JavaScript to the client, which initiates a POST.
Here is an example of using the HttpServletResponse object:
public void service(HttpServletRequest req, HttpServletResponse res)This example tells the client browser to make a GET request to https://loginserver.yourcorp.com/loginservlet?name=val. Because the request is a GET, the user will be able to see the full URL, including the query string in the location bar of the browser. In addition, the amount of information that can be passed using a query string is limited and varies for different Web and app servers. Finally, it's also easier to initiate a replay attack by copying the URL string and pasting it into another browser on a different machine.
throws ServletException, IOException
{res.sendRedirect ("https://loginserver.yourcorp.com/loginservlet? name=val");
...
A better way of redirecting is by using HTML and JavaScript (see Listing 1).
HTML and JavaScript redirects have strong advantages when compared to response.sendRedirect( ). The first advantage is that the HTML form action is a POST. This means the query string information is not visible in the browser location bar. The second is there's no restriction on the amount of information that can be passed to the alternate server. The only drawback is JavaScript has to be enabled on the browser.
If you don't like the idea of shifting the user from one site to the next, JavaScript or hidden frames can be used to communicate with multiple member servers from a single logical page without physically redirecting the browser.
Listing 2 provides a JavaScript example where a page from the login server tells the member servers to set up a session with the browser receiving the page.
The one drawback of using <SCRIPT> tags is that processing is synchronous. The browser has to wait for partner1 to authenticate the browser before attempting partner2. Hidden frames allow you to work asynchronously, although it will only work with a frames-capable browser. See Listing 3 for an example using hidden frames.
The only frame viewable by the user is "viewable". Listing 4 shows what TempFrame.jsp would look like.
In the preceding example, frames "setPartner1cookie" and "setPartner2cookie" log the client browser into other sites asynchronously. Another advantage of using JavaScript or hidden frames is the ability to receive cookies from multiple sites from a single page.
Now that you understand redirection and its alternatives, let's look at cookies.
The Role of Cookies
Most cookies are made up of six parts: name, value, domain, path, expiration date, and secure flag. The name uniquely identifies a single cookie and is used when retrieving, deleting, and updating cookies. The value stores the payload (text) of the cookie. A cookie can hold up to 4K of information. The domain restricts which machine or DNS domains can read an individual cookie. To share cookies between "members.yourdomain.com" and "stocks.yourdomain.com", set your cookies domain to ".yourdomain.com". If you set the cookies domain to "members.yourdomain.com", then the only computer that can read the cookie is "members.yourdomain.com". The path determines which directory can read the cookie and specifies the directory in which files can manipulate a particular cookie.
If you set the path to "/", then any page on the server can read the cookie. The expiration date determines when a cookie is invalidated. The Cookie class has a method, setMaxAge (), which sets how long a cookie should last in seconds. Finally, the secure flag on a cookie ensures that the cookie can be sent only to the client or server over SSL. It doesn't encrypt the information in the cookie file on the client.
Here are several important cookie guidelines.
1. Set the maxAge to -1 to create in-memory cookies.
2. Set the domain to ".yourDomain.com". This allows other machines in your domain to share cookie information directly.
3. Set the path to "/". This allows any of the JSP and servlets on a machine to obtain the cookie, regardless of their location on the machine.
4. Use the Properties object to pass multiple name value pairs within the value of the cookie or request parameter.
5. The secure flag should be set when the login server sets cookies. See Listing 5 for sample code.
To change the value of a cookie or delete a cookie, you'll get the cookie, change an attribute, and send it back using response.addCookie (Cookie changedCookie ). Debugging cookies can be problematic. To minimize debugging time during development, do the following:
1. Set the browser to notify you every time a cookie is set. Go to Tools / Internet Options /Security and select Prompt in both cookies settings. When you get the Security Alert prompt in the browser, you can see all six attributes of a cookie by clicking the "More Info" button.
2. Create a cookie display JSP to print out the cookies and their attributes.
3. Create a cookie delete JSP to delete all of the SSO cookies. We've covered all the components of a Web SSO solution. The last step is the SSO protocol.
SSO Protocol
The SSO protocol describes how browser clients interact with member servers and the login server to enable SSO. The protocol has many variations and you can tailor the protocol presented to suit your needs. The SSO protocol differs slightly, depending on whether all machines participating in SSO reside within the same DNS domain. When machines are under a common domain, cookies set by one machine can be read by another. The LCMServlet on the member server (MS) and login server (LS) serve as the central point of contact for authentication requests and replies. All communication to LCM servlets on MS and LS use HTTPS.
When going from member server to login server, you'll usually have to send the following:
1. Action: This tells the login server what the member server wants, e.g., authenticate, register, etc.
2. Return URL: This is the original URL to a protected resource.
3. Extra information for associated action: This might be a custom login page for the authenticate action.
4. Server identifier: This identifies which server is making the request.
When going from LS to MS, you'll send some or all of the following:
1. User information: This will typically be the user ID and identifying information.
2. Action: Authenticate, register, logout.
3. Result code for initiating action: Failed, successful, etc.
4. Return URL: The return URL represents the original URL that the user was trying to obtain.
5. Timestamp: This is added security to protect against replay attacks. Only requests that have a timestamp less than five- minutes-old will be accepted. Using timestamps requires a clock synchronization service for all servers participating in SSO.
Login Use Case
Remember there are many ways to implement a single sign-on protocol. The actual protocol you'll use depends on your requirements and environment. Figure 2 shows a login use case for servers that share the same DNS domain.
Servers with the Same Domain
1. The user hasn't authenticated and makes a request for a protected resource.
2. The protected resource notices that the user isn't authenticated and redirects the user to the LCMMSServlet passing the requested URL, the server ID, and an action of authenticate.
3. The LCMMSServlet looks for a shared authorization cookie that would have been set by the login server and doesn't find one.
4. The LCMMSServlet takes all the information passed to it and redirects the user to the login server for authentication.
5. The LCMLSServlet receives the request, notices that the user hasn't logged in, and presents a customized login page for the member server that initiated the request.
6. Once the user has successfully authenticated, the login server sets two cookies. The first cookie is an authentication cookie, that stores the user's encrypted authentication information. The second cookie stores the servers that the client has visited (for logout purposes). The login server redirects the user back to the member server's LCMMSServlet with encrypted information in a cookie.
7. The LCMMSServlet decrypts the user information and logs the user in.
8. Once authenticated, the LCMMSServlet forwards the request to a protected resource.
9. If the user tries to access a protected resource on another server in the same domain...
10. The request is redirected to the LCMMSServlet using HTTPS.
11. The LCMMSServlet checks the authenticated cookie and notices that the user has already logged in. The LCMMSServlet sets up a session and writes its server information to the "servers" shared cookie.
12. The LCMMSServlet then forwards the request to a protected resource.
Things will be slightly different if the participating servers reside in different domains. See Figure 3 for an example.
Different Domains
1. The user has not authenticated and makes a request for a protected resource.
2. The protected resource notices that the user is not authenticated and redirects the user to the login server passing the requested URL, the server ID, and an action of authenticate.
3. The login server receives the request, notices that the user hasn't logged in, and presents a customized login page for the member server that initiated the request.
4. Once the user has successfully authenticated, the login server sets two cookies. The first cookie is an authentication cookie, which stores the user's encrypted authentication information. The second cookie stores the servers that the client has visited (for logout purposes). The login server redirects the user back to the member server's LCMMSServlet with encrypted information in a request parameter.
5. The LCMMSServlet decrypts the user information and logs the user in.
6. Once authenticated the LCMMSServlet forwards the request to a protected resource.
7. If the user tries to access a protected resource on another server in the same domain...
8. The request is redirected to the login server using HTTPS.
9. The login server checks the "authorization" cookie and notices that the user has already logged in. The login server adds the new server to the "servers" cookies.
10. Then login server redirects the user back to the member server's LCMMSServlet with encrypted information in a request parameter.
11. The LCMMSServlet decrypts the user information and logs the user in.
12. The LCMMSServlet then forwards the request to a protected resource.
Things are similar in both cases, except the protected resources now redirect to the login server instead of to their local LCMMSServlet. With shared cookies, the member server LCMMSServlets can read the authentication information directly out of the cookie set by the login server. With unshared cookies, the login server needs to tell each member server of a user's status directly (through request parameters) versus indirectly (through a shared cookie).
If all this redirection is making you dizzy, there's a trick you can use to access multiple sites from a single Web page. Let's look at how it works in the logout use case (see Figure 4).
Steps for Multiple Sites
1. The user clicks a logout icon that is linked to the LCMLSServlet of the login server.
2. The login server sends back a temporary page with <SCRIPT> tags or hidden frames.
3. Each of the <SCRIPT> tags of hidden frames contacts a different member server to logout and delete cookies all at once.
4. Once all of the member servers have been contacted, the temporary page is posted back to the login server with the member server logout responses. The login server then sends the logout response page.
The beauty of using hidden frames or a JavaScript SRC attribute is that you go to the login server only once and can access all of the member servers without redirects.
You should have a solid understanding of single sign-on for Web applications. Now we'll discuss single sign-on for standalone applications.
SSO for Standalone Applications
Single sign-on for standalone applications is supported through Kerberos, JAAS, and Sun utility classes. Kerberos provides the single sign-on infrastructure and authentication service. JAAS authenticates users through Kerberos and restricts users based on permissions in a JAAS-specific policy file.
Sun JAAS utility classes (Login and MyAction) help you SSO-enable any Java application. Part 1 discussed Kerberos and JAAS in sufficient detail, so let's look at the Sun utility classes. The Login class encapsulates all of the JAAS-specific code to load the login modules, prompt the user for credentials if necessary, and authenticate the user. The MyAction run( ) method calls the main method of the application that you're SSO-enabling.
To apply what we have learned, let's SSO-enable a Java client application that makes HTTP requests to a Web server.
How to SSO-Enable Java
Let's look at HttpSocketClient.java (see Listing 6). All the client does is open a socket to a Web server HTTP port and read the requested file.
Here are the steps to SSO-enable your Java applications:
1. Get Kerberos set up and running.
2. Use the Login class to serve as an entry point for your application and to initiate the JAAS protocol. The Login class does the following:
3. Create a separate JAR for your application classes. In our case, we have HttpSocketClient.jar containing HttpSocketClient.java.
4. Configure a separate JAAS policy file for your application. Look at the HttpSocketClient.policy file (see Listing 7). Notice that we are using Login.jar to carry out the JAAS protocol and run our application. Login.jar contains both the Login and MyAction classes. We physically separated Sun's utility classes from our application classes so the JAAS classes could run unrestricted. The codebase assumes Login.jar and HttpSocketClient.jar are in the current directory from where you are running the program.
The only client that can run HttpSocketClient is "your_kerb_username". The first permission allows the authenticated user's program to make a socket connection to any host. The second permission allows the client to use the ticket-granting service to get a ticket-granting ticket (TGT). The ticket-granting ticket allows clients to access kerbertized applications without logging in multiple times. The third permission allows the client to initiate a secure context with the specified server_service_principal.
5. Configure the LoginContext configuration file (as specified through the -Djava.security.auth.login.config) to point to Krb5LoginModule. Here is the LoginContext configuration file (sharedLogin.conf ).
HttpSocketClient { com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true; };
The sharedLogin.conf is used to specify the different authentication mechanisms JAAS will use. Here we use the Krb5LoginModule. The Krb5LoginModule interfaces with the Kerberos software client. The "required" flag indicates that this module has to commit successfully for the user to be authenticated. The useTicketCache option tells the LoginModule to look for the ticket-granting ticket in the Kerberos client cache.
If the TGT doesn't exist, JAAS will prompt users for their user IDs and passwords and log them into Kerberos (which generates a TGT). If the TGT exists, the Krb5LoginModule retrieves the principal associated with the TGT. JAAS then checks the Kerberos principal with the principal specified in the JAAS policy file (HttpSocketClient.policy). If the principals match, the application is run using the permissions in the JAAS policy file (HttpSocketClient.policy). If they don't match, the user isn't allowed to run the JAAS-protected application.
6. Run your application through the Login class. To start the application execute the following command on a single line:
java -classpath Login.jar;HttpSocketClient.jarIf you haven't logged into Kerberos with kinit, you will be prompted for your Kerberos credentials. The Login utility class will authenticate you against Kerberos and set up your Kerberos client with a ticket-granting ticket. If the client logged into Kerberos using kinit or Leash32, the Krb5LoginModule will look for his or her TGT in the user cache. The TGT will live on your machine for a default of 600 minutes, so remember to delete your TGT using kdestroy or Leash32 before logging out of your computer.
-Djava.security.manager
-Djava.security.krb5.realm=<your_realm>
-Djava.security.krb5.kdc=<your_kdc>
-Djava.security.policy=HttpSocketClient.policy
-Djava.security.auth.login.config=sharedLogin.conf
Login HttpSocketClient <host> <port_number> <path>
You now have an understanding of single sign-on. You've also seen the issues related to single sign-on - as well as possible solutions. With this practical knowledge in hand, you can now build your own single sign-on solution.
Published December 1, 2001 Reads 19,142
Copyright © 2001 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Abraham Kang
Abraham Kang is an integration architect for
Infogain's Enterprise Integration Solutions group.
His focus is J2EE, security, and enterprise
application integration. Abraham has been
developing in Java for five years.
More Stories By Donald Levy
Donald Levy is the director of alumni relations
and development information systems at Stanford University. Donald has a BS from MIT and an MS from Columbia University.
- Kindle 2 vs Nook
- Why IBM’s Server Chief Got Busted
- Industry Experts Discuss the State of Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Performance Tuning Essentials for Java
- It's the Java vs. C++ Shootout Revisited!
- Confessions of a Ulitzer Addict
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- My Thoughts on Ulitzer
- Oracle-Sun: IBM Reportedly Behind Delay
- Ulitzer Live! New Media Conference & Expo
- Ulitzer Aid Campaign for the Typhoon Ondoy Victims
- Kindle 2 vs Nook
- Cloud CEOs, CTOs & SVPs to Speak at 4th International Cloud Computing Expo
- Why IBM’s Server Chief Got Busted
- Industry Experts Discuss the State of Cloud Computing
- The Difference Between Web Hosting and Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Cloud Computing Journal Opens "Readers' Choice Awards" Nominations
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Performance Tuning Essentials for Java
- It's the Java vs. C++ Shootout Revisited!
- Confessions of a Ulitzer Addict
- The End of IT 1.0 As We Know It Has Begun
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- What's New in Eclipse?
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- i-Technology Predictions for 2007: Where's It All Headed?

































