Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 693
  • Last Modified:

What are cfauthentication and cflogin best practices?

I am setting up user authentication and authorization using the cflogin tag within the application.cfm page.

Depending on the timeout settings for session timeout in the cfapplication tag and idletimeout in the cflogin tag, I have been able to produce situations where I login, then logout and I when I log back in, the cflogin tag does not get called, until it times out, even though the cflogout tag was called.  If I set the idletimeout to a very short timeout, then the cflogin tag will get called, but then if a user is frequently sent back to the login page, the idletimeout seems to kick in and they are sent back to the login page.  

I also have the cflogout in the applcation.cfm and within that, I have code that clears the session structure. I read somewhere that it was a good idea to clear the session vars just in case the user did not close the page.

I am sure I am missing something somewhere.  

Here is my code:   (please note that the LDAP code is not my own, it was derived from Rob Brooks-Bilson's O'Reilly Book "Programming ColdFusion MX"

Application.cfm
===============
<cfapplication name="PortalPrototype"  
          clientmanagement="yes"
          sessionmanagement="yes"
          setclientcookies="yes"
          loginstorage="session"
                                sessiontimeout="#CreateTimeSpan(0, 0, 30, 0)#"
                     applicationtimeout="#CreateTimeSpan(1, 0, 0, 0)#">

<!--- Check to see if the application has been initialized.  If not, set the
      necessary application variables and initialize the app --->
<cflock scope="Application" type="ReadOnly" timeout="5" throwontimeout="No" >
  <cfset IsInitialized = IsDefined('application.Initialized')>
</cflock>    

<cfif not IsInitialized>
   <!--- DEBUG FEEDBACK --->      
   <cfoutput>Application is not initialized.  Initializing now...</cfoutput>    
  <cflock type="Exclusive" scope="Application" timeout="10">
    <cfif not IsDefined('application.Initialized')>
      <cfset application.DSN = "">
      <cfset application.AdminEmail = "">
      <cfset application.Initialized = true>
    </cfif>
  </cflock>
<cfelse>
   <!--- DEBUG FEEDBACK --->      
   <cfoutput>Application is already initialized</cfoutput>
</cfif>


<!--- If the user clicked the logout button or link, log them out --->
<cfif isDefined("URL.Logout")>
                 <!--- DEBUG FEEDBACK --->
     <cfoutput>Logging out...</cfoutput>
     <cfdump var="#session#">
     <cfoutput>#GetAuthUser()#</cfoutput>
     <cflogout>
     <!--- Terminate the user's session by deleting all session variables --->
     <cflock scope="session" type="exclusive" timeout="60" throwontimeout="no">

          <cfset StructClear(session)>
                               <!--- DEBUG FEEDBACK --->
          <cfdump var="#session#">
          <cfoutput>#GetAuthUser()#</cfoutput>
     </cflock>
     
     <!--- added the following cookie code after reading about it at Experts Exchange. --->
     <cfif IsDefined("Cookie.CFID") AND IsDefined("Cookie.CFTOKEN")>
           <cfset cfid_local = Cookie.CFID>
           <cfset cftoken_local = Cookie.CFTOKEN>
           <cfcookie name="CFID" value="#cfid_local#">
           <cfcookie name="CFTOKEN" value="#cftoken_local#">
                 </cfif>

   <cfset URL.message="Thank you for logging out. Please visit again soon!">
   <cfinclude template="loginform.cfm">
     <cfabort>
</cfif>


<cflogin idletimeout="1800" applicationtoken="Portal" cookiedomain=".domain.com">
    <!--- DEBUG FEEDBACK --->
    <cfoutput>We are in the cflogin tag...</cfoutput>    
    <cfdump var="#session#">
     <cfif not isDefined("cflogin")>
          <cfset URL.message="Please log in...">
          <cfinclude template="loginform.cfm">
          <cfabort>
     <cfelse>
         
          <!--- Validate the user and assign roles --->
          <!--- If for some reason username or password is blank, send the user back
          to the login form. --->

          <cfif cflogin.name IS "" OR cflogin.password IS "">
               <cfset URL.message="Either User Name or Password is blank">
               <cfinclude template="loginform.cfm">
               <cfabort>
          <cfelse>
               <!--- Perform the user validation --->

               <!--- setting basic attributes --->
               <cfset LDAP_root = "cn=users,dc=asi,dc=com">
               <cfset LDAP_server = "server.domain.com">
               <cfset LDAP_port = "389">
               <!--- These attributes are used in the first search. --->
               <!--- This filter will look in the object class for the user's ID. --->
               <cfset userfilter = "(&(objectclass=*)(sAMAccountName=#cflogin.name#))">
               <!--- Need directory manager's cn and password to get the user's
               password from the directory --->
               <cfset LDAP_username = "Domain\Server">
               <cfset LDAP_password = "***********">
            <!--- Search for the users's dn information.  This is used later to
                     authenticate the user.
                  NOTE: do this as the Direcotry Manager to ensure access to the information --->
                 
                <cftry>
                    <cfldap name="userSearch"
                      action="query"
                      attributes="cn,dn,sAMAccountName,mail"
                      start="#LDAP_root#"
                      scope="subtree"
                      server="#LDAP_server#"
                      port="#LDAP_port#"
                      filter="#userfilter#"
                      username="#LDAP_username#"
                      password="#LDAP_password#"
                    >
                   
                    <cfcatch type="any">
                  <!--- DEBUG FEEDBACK --->          
                                        <cfoutput>Error: #cfcatch.Message#. Type: #cfcatch.Type#  Code:000100</cfoutput>
                         <cfset UserSearchFailed = true>
                    </cfcatch>
                </cftry>
                     
       <!--- If user search failed or returns 0 rows, abort --->
               <cfif  NOT userSearch.RecordCount OR isDefined("UserSearchFailed")>
                    <cfset URL.message="Login error">
                    <cfinclude template="loginform.cfm">
                    <cfabort>
               <cfelse>
               
               </cfif>
       <!--- Pass the user's DN and password to see if the user authenticates.
                 and get the user's roles --->
               <cftry>
                    <cfldap
                          action="query"
                          name="auth"
                          attributes="cn"
                          start="cn=users,dc=asi,dc=com"
                          scope="subtree"
                          server="#LDAP_server#"
                          port="#LDAP_port#"
                          filter="(&(objectclass=group)(member=#userSearch.dn#))"
                          sort="cn"
                          username="#userSearch.mail#"
                          password="#cflogin.password#"
                     >
                     <cfcatch type="any">
                          <cfif FindNoCase("Invalid credentials", cfcatch.Detail)>
                              <cfset URL.message="Error: #cfcatch.Message#. Type: #cfcatch.Type#  Code: 000101 Username or Password invalid for user: #cflogin.name#">
                              <cfinclude template="loginform.cfm">
                              <cfabort>
                         <cfelse>
                              <cfset URL.message="Unknown error for user: #cflogin.name# #cfcatch.Message# Try logging in again">
                              <cfinclude template="loginform.cfm">
                              <cfabort>
                         </cfif>
                     </cfcatch>
               </cftry>
                                                 <!--- DEBUG FEEDBACK --->
                <cfoutput> User lookup successful... </cfoutput>
      <!---  If the LDAP query reutrned a record, the user is valid. --->
               <cfif auth.recordcount>
                                                <!--- DEBUG FEEDBACK --->
               <cfoutput>LDAP user search OK: #auth.recordcount#</cfoutput>
                   
                                <cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="#valueList(auth.cn)#">
                                                                <!--- DEBUG FEEDBACK --->                    
                                                               <cfoutput>
                    We are in the cfloginuser tag
                    <br>cflogin.name:  #cflogin.name#
                    <br>cflogin.password: #cflogin.password#
                    <br>cflogin.roles: #valueList(auth.cn)#
                   
                    </cfoutput>
                    <!--- save some session variables --->
                    <cfoutput> setting up session variables... </cfoutput>
                    <cflock name="sLogin_Lock" timeout="30" type="exclusive">
                         <cfset session.Email = #userSearch.mail#>
                         <cfset session.cn = #userSearch.cn#>
                         <cfset session.dn = #userSearch.dn#>
                         <cfset session.userID = #cflogin.name#>
                         <cfset session.LogInTime = Now()>
                         <cfset session.NumberOfGroups = auth.recordcount>
                         <cfset session.RoleList = #valueList(auth.cn)#>
                         <cfset session.FullName = #session.cn#>
                         <cfset session.authenticated = true>
                    </cflock>
                   
                    <!--- If save username box is checked, set cookie --->
                    <cfif IsDefined('form.SaveUsername')>
                      <cfcookie name="Username" value="#cflogin.Name#">
                    </cfif>        
               <cfelse>
                                                               <!--- DEBUG FEEDBACK --->
                    <cfoutput> LDAP UserSearch query failed...</cfoutput>
                    <cfset URL.message="Unknown error for user: #cflogin.name# Contact a member of Infotech to resolve the problem.">
                    <cfinclude template="loginform.cfm">
                    <cfabort>
               </cfif>
          </cfif>
     </cfif>
</cflogin>

0
maplesoft
Asked:
maplesoft
  • 3
1 Solution
 
mrichmonCommented:
Here is an authentication best practice doc:

http://www.macromedia.com/devnet/mx/coldfusion/articles/ntdomain.html

Basically things to watch out for/general login best practices

1. alwyas check both username and password
2. do not tell the user why the login failed - display a generic message like "Username or password is incorrect"  By telling them only the password was worng then they know the login is valid and can keep attempting t o hack your system.  Valid users will know if the username had a mistake or not.
3. Always encrypt password information - it is best to hash and then only compare hashes so you never are storing user passwords
0
 
maplesoftAuthor Commented:
I have seen the ntdomain article before and maybe I will use an alternate method instead of cfldap.

I was looking for some feedback on the code I posted and for information on the optimum idle timeouts for the cflogin and session timeout for the cfapplciation.

I guess I was hoping for responses from a few more experts by awarding a lot of points.  

Can we give this a couple more weeks, or renew it?  

Thanks.
0
 
mrichmonCommented:
We can leave it open a bit longer, but chances are no one else will respond since it is an older question.

And any responses you get would most likely be very similar.  Best practices don't change very often and when they do it is usually only slightly unless the technology significantly changes.
0
 
mrichmonCommented:
I am recommending that this question now be closed as originally recommended since there have been no further comments.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now