Oracle database design, development and administration
Data Management
Project Management
Cryptic crossword.
A bit about me.
Read my blog
Recent additions
Home

  • Creating a CF login system for Oracle:


    Note: The Oracle-related material presented here is largely ColdFusion-version independent. However, please note that most of the ColdFusion code has been developed and tested on older versions of ColdFusion (4.0 through 6.0). Consequently, some CFML code snippets may need to be modified to work optimally on more recent versions of the product.

    Creating a login system for Oracle is really quite simple. Basically you need a login page and an action page that does the necessary validation against Oracle and sets session variables with the userid, password and datasource names. Thereafter, on every secured page you need to check that the user has been validated. This is best done through a snippet of code that is cfincluded into each secured template. Finally, you need a logout template that destroys the user's session. What follows is a detailed discussion on how to build each of the components described above.

    In the discussion I assume that users are to be validated against their Oracle userid/password, and that these have already been created in Oracle.

    The first thing is to ensure that session management is switched on for the application, as this is the only way to maintain user state between requests. This is best done in your application.cfm template, since this is executed with every request:

    <!---excerpt from application.cfm---!>

    <cfapplication name="YourAppName"
       sessionmanagement="Yes"
      setclientcookies="Yes">

    Here I have assumed that users are not averse to accepting cookies. If your users are not thus inclined, you'll have to pass the session tokens through the URL - but we'll not go through that tedious exercise here.

    The next step is to create the login page. The body of this page would contain something similar to following html:

    <!---excerpt from login.cfm--->

    <form action="login_action.cfm" method="post">

      Login:<input type="text" name="uid">

      Password:<input type="password" name="pwd">

      Datasource:<input type="text" name="dsn">

      <input type="button" value="Login" onclick="submit()">

    </form>

    Just one point here: you could hardcode your datasource name in your application.cfm file if you prefer.

    The action template for login.cfm contains a whole lot of validation code followed by a simple database query. If all is well, session variables for the userid, password and DSN are set. If not, the user is asked to login again:

    <!---excerpt from login_action.cfm--->

    <cftry>

    <cfif IsDefined("form.uid") AND IsDefined("form.pwd") AND IsDefined("form.dsn")>

      <cfif Trim(Len(form.uid)) EQ 0 OR Trim(Len(form.pwd)) EQ 0 OR Trim(Len(form.dsn)) EQ 0>

        <cfthrow message="User name, password or datasource blank.">

       <cfelse>

        <!--- check if the user has basic select privileges --->

         <cfquery datasource="#form.dsn#"
          username="#form.uid#"
           password="#form.pwd#"
          maxrows=1
          name="check_authorization">

          select
            count(*)
           from
            all_tables

        </cfquery>

        <cflock timeout="15">

          <cfset Session.uid = UCase(form.uid)>
           <cfset Session.pwd = form.pwd>
          <cfset session.dsn=form.dsn>

         </cflock>

       </cfif>

    <cfelseif (NOT IsDefined("Session.uid"))>

      <cfthrow message="User not logged in, or session timed out.">

    </cfif>

    <!---Your code goes here---!>

    <cfcatch>

       An authorization error has occurred

      Message: <cfoutput>#cfcatch.message#</cfoutput>

      Please click on the button to login.

      <input type="button" value="Login" onclick="location.replace('login.cfm')">

    </cfcatch>
    </cftry>


    Several things need elaboration here:
    1. The code is enclosed in a cftry block to allow the use of cfcatch to handle exceptions (such as failed login attempts).
    2. The first couple of cfifs check that the appropriate form variables are defined, and that they are not blank.
    3. If the tests in (2) are passed, a simple query is sent on to Oracle. This query should be against a table or view that the user is expected to have select privileges on. ALL_TABLES is a view that is a part of the Oracle data dictionary. This view lists all tables to which the user has access, so it is a good candidate. You can read more about this and other data dictionary views in the Oracle docs, or in my CFDJ article on building a database monitor using CF.
    4. If the query is successful we set session variables to hold the userid, password and DSN. These will be used in queries on subsequent pages.
    5. You then insert whatever code you want in the placeholder that follows the cfif block. This is typically code you want only authorized users to access and execute.
    6. Finally, the cfcatch section traps authorization errors and gives the user an opportunity to login again. Note that you could trap specific database errors using cfcatch. A "how-to" on this topic can be found here.

    Now, how can we maintain user state in subsequent templates? This is done very simply by cfincluding the following snippet at the top of all templates that use the set session variables. These are basically any templates that access the database.

    <!--- inc_session_test.cfm---!>

    <cfif NOT IsDefined("session.uid")>

       Authorization error: User not logged in or session timed out.

      Please click on the button to login.

      <input type="button"
        value="Login"
        onclick="location.replace('login.cfm')">

      <cfabort>

    </cfif>


    This snippet should be included at the top of all password protected pages, like so:

    <!--- protected_template.cfm--->

    <cfinclude template="inc_session_test.cfm">

    <!---protected code goes here--->


    The cfabort guarantees that processing will stop before the protected code is reached, if the user is not authenticated.

    Finally, in our logout template, we simply loop through the session structure and destroy all set session variables. Here's the relevant excerpt from logout.cfm:

    <!--- from logout.cfm--->

    <cfset user=session.uid>

    <cfloop collection=#session# item="i">

      <cfset StructDelete(session,i)>

    </cfloop>

    User <cfoutput>#user#</cfoutput> has been logged out of YourApp.

    Please click on the button below if you want to login again.

    <input type="Button"
      value=" Login"
      onClick ="location.replace('login.cfm')">


    Links or buttons to the above template can be placed on all protected pages from which you want the user to be able to logout. Upon clicking the link/button the user's session is destroyed by the above code. In my apps, I usually pad up the onclick JavaScript to present the user a "confirm" box before they are redirected to the logout page. This enhancement will help prevent unintended logouts- I have noticed that some users tend to click buttons all over the place without thinking of the consequences!

    This brings me to the end of the discussion. I don't claim that this is the best way of building a login system, and the code is far from optimal. However, it is offered up here as a guide to help you build your own.

    Back to the top