Skip to end of metadata
Go to start of metadata
Table of Contents

Christian Stuck of Westminster Choir College contributed this information about authentication of ColdFusion applications on the CAS Mailman list:

This is a simple CAS script we developed to replace an existing simple login script for a problem solving ColdFusion application we have. This is not very elegant (esp. not with XML), but it will get the job done. You will have to go through and change some variables, along with the SQL statement:

<!--- // Login.cfm

// ColdFusion MX 6.1 code that uses CAS 2.0

// Christian Stuck
// stuckc@rider.edu
// Westminster Choir College
// Princeton, New Jersey --->

<cflock scope="Session" type="ReadOnly" timeout="30" throwontimeout="no">
 <cfset
MM_Username=Iif(IsDefined("Session.MM_Username"),"Session.MM_Username",DE(""
))>
 <cfset
MM_UserAuthorization=Iif(IsDefined("Session.MM_UserAuthorization"),"Session.
MM_UserAuthorization",DE(""))>
</cflock>
<!--- // Insert name of CAS Server at your location --->
<cfset CAS_Server = "https://yourserver/cas/">

<!--- // Insert public name of IIS Server hosting this script
// Note: CGI.HTTP_HOST or anything based on
// the HTTP "Host" header should NOT be used; this header is supplied by
// the client and isn't trusted. --->
<cfset MyServer = "https://yourserver/yourwebapp/">

<!--- See if already logged on --->
<cfif MM_Username EQ "">
<!--- Check for ticket returned by CAS redirect --->
<cfset ticket=Iif(IsDefined("URL.ticket"),"URL.ticket",DE(""))>
<cfif ticket EQ "">
  <!--- No session, no ticket, Redirect to CAS Logon page --->
       <cfset casurl = #CAS_Server# & "login?" & "service=" & #MyServer# &
"/login.cfm">
       <cflocation url="#casurl#" addtoken="no">
<cfelse>
<!--- Back from CAS, validate ticket and get userid --->
<cfset casurl = #CAS_Server# & "serviceValidate?ticket=" & #URL.ticket# &
"&" & "service=" & MyServer & "/login.cfm">
<!---        http.open("GET",url,false); // HTTP transaction to CAS server
       http.send(); --->
<cfhttp url="#casurl#" method="get"></cfhttp>
<cfset objXML = xmlParse(cfhttp.filecontent)>
<cfset SearchResults = XmlSearch(objXML,
"cas:serviceResponse/cas:authenticationSuccess/cas:user")>
<cfif NOT ArrayIsEmpty(SearchResults)>
<cfset NetId = #SearchResults[1].XmlText#>
<cfelse>
       <cfset casurl = #CAS_Server# & "login?" & "service=" & #MyServer# &
"/psal/casexample.cfm">
       <cflocation url="#casurl#" addtoken="no">
</cfif></cfif></cfif>

 <cfset MM_redirectLoginSuccess="index.cfm">
 <cfset MM_redirectLoginFailed="accessdenied.cfm">

<!--- Your SQL Statement to access authorized user table/view --->
<cfquery  name="MM_rsUser" datasource="#DATASOURCE#">
 SELECT netId, universityId, firstName, lastName
 FROM Person WHERE netId='#NetId#'
 </cfquery>

<!--- If the user was found in the authorized user table/view, proceed --->
<cfif MM_rsUser.RecordCount NEQ 0>
   <cftry>
     <cflock scope="Session" timeout="30" type="Exclusive">
       <cfset Session.MM_Username=MM_rsUser.NetId>
       <cfset Session.MM_universityId=MM_rsUser.universityId>
       <cfset Session.MM_firstName=MM_rsUser.firstName>
       <cfset Session.MM_lastName=MM_rsUser.lastName>
       <cfset Session.MM_UserAuthorization="">
     </cflock>
     <cfif IsDefined("URL.accessdenied") AND true>
       <cfset MM_redirectLoginSuccess=URL.accessdenied>
     </cfif>
     <cflocation url="#MM_redirectLoginSuccess#" addtoken="no">
     <cfcatch type="Lock">
       <!--- code for handling timeout of cflock --->
     </cfcatch>
   </cftry>
 </cfif>

<!--- If the user was not found in the authorized user table/view, deny
access --->
<cflocation url="#MM_redirectLoginFailed#" addtoken="no">

This way of authenticating also requires you to have a script named
Application.cfm with the following line:

<cfapplication name="Name of Application" clientmanagement="yes"
sessionmanagement="yes" setclientcookies="yes" setdomaincookies="no"
loginstorage="session">

What does this script do? How do you consume its output? Well,

It sets the authenticated username from the XML response

( #SearchResults[1].XmlText# ) 

in the NetId variable.

<cfset NetId = #SearchResults[1].XmlText#>

It then sets the Session variable of MM_UserName to this NetId variable so that all ColdFusion pages in the application can access it.

<cfset Session.MM_UserName=NetId />
  • No labels

2 Comments

  1. Thanks Christian this code was great. Using <cfhttp> over SSL gave us some problems though. Read this post from bpurcell.org to remedy any problems: http://www.bpurcell.org/blog/index.cfm?mode=entry&entry=843

    If you have had problems connecting CFHTTP using HTTPS then the following forum posting may help you out.

    It ended up being because the server we were connecting to used certificates and the Java didn't like them. To fix it we exported the certificates from IE Certificate manager after installing them from thier website and the entie certificate chain if neccessary (root, and intermediates)...

    Export each to c:\cfusion\runtime\jre\lib\security (Assuming CF is installed at this location) using the bianry x.509 format (The default for IE 6). Name them something recognisable (Site1.cer, site2.cer and site3.cer in this case)
    Easy part is done.

    Now, run a command line (CMD at Start-Run)
    type PATH=%PATH%;C:\CFUSIONMX\RUNTIME\JRE\BIN (Assuming CF is installed at this location)
    cd\
    cd cfusionmx\runtime\jre\lib\security
    keytool -import -noprompt -alias SITE1 -file site1.cer -keystore .\cacerts -storepass changeit (assuming you haven't changed the default java password yet)
    keytool -import -noprompt -alias SITE2 -file site2.cer -keystore .\cacerts -storepass changeit
    keytool -import -noprompt -alias SITE3 -file site3.cer -keystore .\cacerts -storepass changeit
    exit

    Now restart the CF Services or restart the server and it should work.

  2. Below is some sample code we developed to test CAS out without the CAS login screen, adapted from Christian Struck's original code.

    <!---
    // Login.cfm

    // Cynthia Reece
    // Using CAS without the CAS login screen
    // Adapted from Christian Stuck's CAS Client Script Code
    // Monday, May 23 2005

    --->

    <cfif NOT isDefined("url.ticket")>
    <!--- go to cas to get the login ticket which will get passed with the username and password --->
    <cftry>
    <cfhttp
    method="get"
    url="#CAS_Server_insecure#/login?service=#MyApp#/login.cfm">

    <!--- Back from CAS
    parse through the text to extract the login ticket
    Login ticket will get passed with the username and password via next http call --->

    <cfset loginTicketLocation = REFindNoCase("LT-0-9-A-Za-z0-9", cfhttp.filecontent, 1, "True")>
    <cfset loginTicket = Mid(cfhttp.filecontent, loginTicketLocation.pos1, loginTicketLocation.len1)>
    <cfcatch>
    <p>We're sorry the authentication server is unavailable at this time, please try again later.</p>
    <cfabort>
    </cfcatch>
    </cftry>

    <!--- Go back to CAS and try to log in with the username and password specified by the user, plus the login ticket
    we just obtained from CAS --->
    <cftry>
    <cfhttp method="post"
    url="#CAS_Server_insecure#/login?service=#MyApp#/login.cfm">
    <cfhttpparam type="FormField"
    name="username"
    value="#username#">
    <cfhttpparam type="FormField"
    name="password"
    value="#password#">
    <cfhttpparam type="FormField"
    name="lt"
    value="#loginTicket#">
    </cfhttp>

    <!--- Check to see if CAS returned a valid Ticket Granting Cookie
    parse through the text to extract the ticket granting cookie --->
    <cfset TicketGrantingCookieLocation = REFindNoCase("TGC-0-9-A-Za-z0-9", cfhttp.header, 1, "True")>
    <cfset TicketGrantingCookie = Mid(cfhttp.header, TicketGrantingCookieLocation.pos1, TicketGrantingCookieLocation.len1)>
    <!--- Set cookie via cfheader because we must specify the character set.
    cfcookie uses the UTF character set --->
    <cfheader
    name="Set-Cookie"
    value="CASTGC=#TicketGrantingCookie#; Path=/cas; Secure Content-Type: text/html;charset=ISO-8859-1; domain=.yourdomain.org;">

    <!--- If a valid ticket is returned the contents of this variable will contain a javascript redirect back to this page
    and also some 'click here' text if the user has javascript disabled --->
    <cfoutput>#cfhttp.filecontent#</cfoutput>
    <cfcatch>
    <p>We're sorry the username and password you entered is invalid.</p>
    </cfcatch>
    </cftry>

    <cfelse>
    <!--- Now we've gotten the service ticket so we must validate it --->
    <cfset casurl = CAS_Server & "serviceValidate?ticket=" & url.ticket & "&service=" & MyApp & "/login.cfm">
    <cfhttp url="#casurl#" method="get"></cfhttp>
    <!--- Strip out the username that is returned from CAS --->
    <cfscript>
    myxmldoc = XmlParse(cfhttp.filecontent);
    selectedElements = XmlSearch(myxmldoc, "cas:serviceResponse/cas:authenticationSuccess/cas:user");
    if(isArray(selectedElements) AND NOT ArrayIsEmpty(selectedElements)) {
    //valid ticket found
    ULuserid = selectedElements1.XmlText;
    }
    else
    //invalid ticket
    ULuserid = 0;
    </cfscript>

    <!--- Set the username in the session --->
    <cfset Session.MM_ULuserID=selectedElements1.XmlText>

    <cflocation url="index.cfm" addtoken="no">

    <!--- Now that we have the username we should go ahead and set some permissions --->
    </cfif>