Solved

What are cfauthentication and cflogin best practices?

Posted on 2004-10-14
6
651 Views
Last Modified: 2013-12-24
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
Comment
Question by:maplesoft
  • 3
6 Comments
 
LVL 35

Accepted Solution

by:
mrichmon earned 500 total points
ID: 12313325
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
 

Author Comment

by:maplesoft
ID: 12571724
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
 
LVL 35

Expert Comment

by:mrichmon
ID: 12584845
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
 
LVL 35

Expert Comment

by:mrichmon
ID: 12879232
I am recommending that this question now be closed as originally recommended since there have been no further comments.
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Most ColdFusion developers get confused between the CFSet, Duplicate, and Structcopy methods of copying a Structure, especially which one to use when. This Article will explain the differences in the approaches with examples; therefore, after readin…
Meet the world's only “Transparent Cloud™” from Superb Internet Corporation. Now, you can experience firsthand a cloud platform that consistently outperforms Amazon Web Services (AWS), IBM’s Softlayer, and Microsoft’s Azure when it comes to CPU and …
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now