ColdFusion MX 7 Login Security (Page 7 of 13)

The onRequestStart Method (continued)

108.    <cfif NOT isDefined("request.User.LoggedIn")>
115.       <cfinclude template="login.cfm">
116.       <cfabort>
117.    <cfelse>
119.       <cflock scope="SESSION" throwontimeout="Yes" timeout="7" type="EXCLUSIVE">
120.          <cfset Session.User = Duplicate(request.User)>
121.       </cflock>
127.       <cflock name="lck_currentSessions" throwontimeout="Yes" timeout="7"
129.          <cfset Application.currentSessions = Application.currentSessions + 1>

132. <cfif NOT isDefined("Application.sessionData")> 133. <cfset Application.sessionData = ArrayNew(1)> 134. </cfif> 135. <cfset ArrayAppend(Application.sessionData, Session.sessionid)> 136. </cflock> 139. <cfif NOT isDefined("session.requestedPage") OR Find("authenticate.cfm", session.requestedPage)> 140. <cfset session.requestedPage = "index.cfm"> 141. </cfif> 142. <cflocation url="##session.requestedPage##"> 143. </cfif> 144. </cfif>

Since both the username and password were entered correctly, the Request.User structure was created along with several keys. This will cause the conditional logic on line 108 (above) to evaluate to FALSE causing the else block to be processed. Inside the else block, we do several things. First, we duplicate the temporary Request.User structure into a newly created session structure. Next, we write some simple code for tracking user sessions. The basic idea here is to store how many users are currently logged in to the system in the Application scope. We do this by simply incrementing the Application.currentSessions variable (initialized in the onApplicationStart method) by one. Then, we provide some checks and balances against our session counter by also storing the unique sessionid for each logged in user in an array called Application.sessionData. This array will prove very handy when it comes time to handle how users get logged out of the system. So why is all this session tracking code executed in a named CFLOCK? Normally, you would lock access to the Application scope using an Application-scoped lock. However, just as we have to track how a user logs in we also have to track how they log out. Given the way we are going to do this (in the onSessionEnd method and logout.cfm) it will be necessary for us to use a named lock. I'll explain this in more detail when we get to the logout portion.

Finally, on line 139 we check to see that session.requestedPage is defined. We haven't talked about the code that displays the login template, but this variable gets defined there so we can handle "smart redirects." Essentially, this variable gets set to the value of CGI.SCRIPT_NAME when the login form displays. This allows us to store which Web page the user requested when they have not authenticated to the system. Once they have authenticated, we'll redirect them to their requested page instead of the main page of the application. Revisiting line 139, if session.requestedPage is not defined or it's a value we don't want the user to redirect to (like our custom, not-for-display authenticate.cfm template), we set the value to our main index page as the default. Then, we redirect the user to the appropriate page.