Welcome!

ColdFusion Authors: Maureen O'Gara, Hovhannes Avoyan, Yakov Fain, Pat Romanski, Liz McMillan

Related Topics: ColdFusion

ColdFusion: Article

ColdFusion Developer's Journal: Implementing a Single Sign-On Solution Using CF

Constructing a single sign-on solution for Web applications

Now that we have created our session and have the necessary cookies in place, it's time to log the user in. Before we get to the code, let's discuss a few different ways to get the username and password. We could ask for all user accounts up front and enter them in a database manually, but if you have many users, that could take time and resources. One solution is when users log in and click the link to use single sign-on, we can check to see if they have a password in our database. If they don't, we make them key it in and store the credentials with the password encrypted. From then on, when users access single sign-on, we'll have their credentials locally stored in a database that we can pass on to the target system. The only drawback is that if the account expires, the user will have to reenter their credentials into our system. Depending on the target application, you might be able to automate some of that through code. Once we have obtained the credentials, we can log the user in by passing them as <CFHTTPPARAM> attributes:

<!--- send the user credentials with previous cookies via HTTP post--->
<cfhttp method="post" url="http://
testsso.com/processlogin.cfm;jsessionid=#cookieStruct.JSESSIONID#">
   <cfloop collection="#cookieStruct#" item="key">
   <cfhttpparam type="cookie" name="#key#" value="#cookieStruct[key]#">
   </cfloop>
   <cfhttpparam type="formfield" name="username" value="user1">
   <cfhttpparam type="formfield" name="password" value="mypwd">
</cfhttp>

It is important to remember to send the cookies during every http request since HTTP is stateless and that's how we are maintaining session. One thing you might have noticed - the URL has the following code attached to it: ';jsessionid=#cookieStruct.JSESSIONID#'. If your target application is running ColdFusion with J2EE session variables enabled or it's running any other J2EE server, you must pass the jsessionid as part of the URL. The fact that I'm accessing the jsessionid in the cookie structure by name means that I'm expecting it to be present. However, if you would like to write a single sign-on application that's generic enough to work with any system, you should first search for the jsessionid in the cookie structure. If it's there, append it to all HTTP URLs. One other gotcha: if you do append the jsessionid as part of the URL, IIS might think it's actually part of the URL and return a 404 Page Not Found error. If you have that problem, there is a ColdFusion Technote documenting the problem and resolution on Macromedia's Web site (www.macromedia.com/cfusion/knowledgebase/index.cfm?id=1c6b723). It's a simple fix and requires a small edit to the JRUN.INI file on the target system.

At this point the user is logged into the system and we have all the cookies stored in a structure. It's worth mentioning that we should check to see if any cookies are passed back from any of our HTTP requests and either add them to or update our cookie structure. My example assumes that no cookies are sent to the client during any other HTTP request other then the initial HTTP GET operation on the login.cfm page. From our earlier research we know what page the user is sent to after login. We can perform an HTTP GET on this page to verify the user is successfully logged into the system:

<!--- redirect user to main page of new application--->
  <cfhttp method="get"
url="http://testsso.com/index.cfm;jsessionid=#cookieStruct.jsessionid#">
   <cfloop collection="#cookieStruct#" item="key">
    <cfhttpparam type="cookie" name="#key#" value="#cookieStruct[key]#">
   </cfloop>
</cfhttp>

If this request doesn't work, the target system will most likely send us back to the main login page or an unsuccessful login page; however, if the page we requested is sent back to us, then we verified that the user is logged in. Usually we can check for some type of "signature" in the HTTP response to let us know which case we're dealing with. In my example I'm assuming everything is working fine (because it always does...right?).

Our end goal is to provide a new window to the user that displays the target application with the user already logged into the system. We currently have logged the user in and have a structure containing the authentication cookies. We now need to get the cookies into the browser and open a new window with the target application. There are two main paths we can travel to get this done and it all depends on our environment, namely, if both the target system and the system providing single sign-on access are both on the same domain. If both systems are on the same domain, we can use JavaScript to write cookies to the browser and open a new window. Most browsers maintain cookies when a new window is opened, which will in turn maintain our session. Since both of our systems are part of the same domain, the browser will continue to send the cookies to the target system after we make our hand off to the new browser window. We just need to make sure that the cookies are written before the window is opened. To do this we can use the following JavaScript:

<script language="javascript">
<cfloop collection="#cookieStruct#" item="key">
document.cookie='#key#=#cookieStruct.jsessionid#;path=/';
</cfloop>
window.open('http://testsso.com/index.cfm;jsessionid=#cookieStruct.jsessionid#',
'SelectWindow','width=800,height=300);
</script>

After the above code has been sent to the browser, our mission is done. The above code writes the necessary cookies to the browser and a new window will open that will effectively give up control to the target application.

Now, we must consider the case where our systems are not on the same domain. This presents a problem because cookies cannot be set and accessed across domains for security reasons. Imagine if you could read and write cookies from other domains (like online banking applications). Session cookies and security of those sessions would fall apart; the cookies would crumble (sorry, I had to). Therefore, we need to construct a way to write our cookies to the browser from the domain of the target application. We can do this by passing our cookies to an HTML file on the target server domain that will write the cookies to the browser for us and redirect the user to the target application. Here is an example of what the HTML file might look like (also in Listing 2):

<SCRIPT language="JavaScript1.1">
var queryString = document.location.search;

// take out ? to get query string
queryString = queryString.substring( 1 );

// parse parameters based on &
var cookies= queryString.split( '&' );
for ( i=0; i<cookies.length; i++ ){
document.cookie=unescape(cookies[i]);
}

document.location.replace('http://testsso.com/index.cfm');
</SCRIPT>

More Stories By Steven Forehand

Steven Forehand is the team manager for the New Technologies Development Group, a team of twelve talented application developers at East Carolina University located in Greenville, North Carolina. He has been using Macromedia ColdFusion since just prior to version 2 and has over nine years of software development experience and is Macromedia ColdFusion MX certified

More Stories By Zachary Loch

Zachary Loch, a Macromedia Certified Advanced ColdFusion MX Developer, is project manager of application development at East Carolina University and also works on special data integration projects. He has 8 years of software development experience in a diverse set of industries including healthcare, insurance, education, and telecommunications.

Comments (3) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Casey Priest 11/18/05 12:07:02 PM EST

I receive this error when trying to use the code:

Element Set-Cookie is undefined in a CFML structure referenced as part of an expression.

I really need this work - any ideas?

CFDJ News Desk 10/19/05 09:42:09 AM EDT

Implementing a Single Sign-On Solution Using CF. There is an evolution that takes place when organizations start to develop Web applications as part of their IT infrastructure. Initially, an application is written for a particular purpose, say a contact management system or an inventory control system.

INGR8 10/19/05 09:14:45 AM EDT

|| The obvious drawback to this approach is that you must have permission or access to set the setCookies.html file on the target domain ||

Good point.