Application-based user security example



The following example shows how to implement user security by authenticating users and then allowing users to see or use only the resources that they are authorized to access.

This example has three ColdFusion pages:

  • The Application.cfc page contains the authentication logic that checks whether a user is logged in, requests the login page if the user is not logged in, and authenticates the data from the login page. If the user is authenticated, it logs the user in.

    This page also includes the one-button form and logic for logging out a user, which appears at the top of each page.

  • The loginform.cfm page displays the login form. The code on this page could also be included in Application.cfc.

  • The securitytest.cfm page is a sample application page. It displays the logged-in user’s roles.

Test the security behavior by adding your own pages to the same directory as the Application.cfc page.

The example gets user information from the LoginInfo table of the cfdocexamples database that is installed with ColdFusion. You can replace this database with any database containing UserID, Password, and Roles fields. The sample database contains the following data:

UserID

Password

Roles

BobZ

Ads10

Employee,Sales

JaniceF

Qwer12

Contractor,Documentation

RandalQ

ImMe

Employee,Human Resources,Manager

Because spaces are meaningful in roles strings, do not follow the comma separators in the Roles fields with spaces.

Example: Application.cfc

The Application.cfc page consists of the following:

<cfcomponent> 
<cfset This.name = "Orders"> 
<cfset This.Sessionmanagement="True"> 
<cfset This.loginstorage="session"> 
 
<cffunction name="OnRequestStart"> 
    <cfargument name = "request" required="true"/> 
    <cfif IsDefined("Form.logout")> 
        <cflogout> 
    </cfif> 
 
    <cflogin> 
        <cfif NOT IsDefined("cflogin")> 
            <cfinclude template="loginform.cfm"> 
            <cfabort> 
        <cfelse> 
            <cfif cflogin.name IS "" OR cflogin.password IS ""> 
                <cfoutput> 
                    <h2>You must enter text in both the User Name and Password fields. 
                    </h2> 
                </cfoutput> 
                <cfinclude template="loginform.cfm"> 
                <cfabort> 
            <cfelse> 
                <cfquery name="loginQuery" dataSource="cfdocexamples"> 
                SELECT UserID, Roles 
                FROM LoginInfo 
                WHERE 
                    UserID = '#cflogin.name#' 
                    AND Password = '#cflogin.password#' 
                </cfquery> 
                <cfif loginQuery.Roles NEQ ""> 
                    <cfloginuser name="#cflogin.name#" Password = "#cflogin.password#" 
                        roles="#loginQuery.Roles#"> 
                <cfelse> 
                    <cfoutput> 
                        <H2>Your login information is not valid.<br> 
                        Please Try again</H2> 
                    </cfoutput>     
                    <cfinclude template="loginform.cfm"> 
                    <cfabort> 
                </cfif> 
            </cfif>     
        </cfif> 
    </cflogin> 
 
    <cfif GetAuthUser() NEQ ""> 
        <cfoutput> 
                <form action="securitytest.cfm" method="Post"> 
                <input type="submit" Name="Logout" value="Logout"> 
            </form> 
        </cfoutput> 
    </cfif> 
 
</cffunction> 
</cfcomponent>

Reviewing the code

The Application.cfc page executes before the code in each ColdFusion page in an application. For more information on the Application.cfc page and when it is executed, see Designing and Optimizing a ColdFusion Application.

The following table describes the CFML code in Application.cfc and its function:

Code

Description

<cfcomponent> 
<cfset This.name = "Orders"> 
<cfset This.Sessionmanagement="True"> 
<cfset This.loginstorage="session"> 
 
<cffunction name="OnRequestStart"> 
    <cfargument name = "request" required="true"/>

Identifies the application, enables session management, and enables storing login information in the Session scope.

Begins the definition of the onRequestStart method that runs at the starts of each request.

<cfif IsDefined("Form.logout")> 
    <cflogout> 
</cfif>

If the user just submitted the logout form, logs out the user. The following cflogin tag runs as a result.

<cflogin> 
    <cfif NOT IsDefined("cflogin")> 
        <cfinclude template="loginform.cfm"> 
        <cfabort>

Runs if there is no logged-in user.

Tests to see if the user has submitted a login form. If not, uses cfinclude to display the form. The built-in cflogin variable exists and contains the user name and password only if the login form used j_username and j_password for the input fields.

The cfabort tag prevents processing of any code that follows on this page.

<cfelse> 
    <cfif cflogin.name IS "" OR cflogin.password IS ""> 
        <cfoutput> 
        <h2>You must enter text in both the User Name and Password fields. </h2> 
        </cfoutput> 
        <cfinclude template="loginform.cfm"> 
        <cfabort>

Runs if the user submitted a login form.

Tests to make sure that both name and password have data. If either variable is empty, displays a message, followed by the login form.

The cfabort tag prevents processing of any code that follows on this page.

<cfelse> 
    <cfquery name="loginQuery" dataSource="cfdocexamples"> 
    SELECT UserID, Roles 
    FROM LoginInfo 
    WHERE 
    UserID = '#cflogin.name#' 
    AND Password = '#cflogin.password#' 
    </cfquery>

Runs if the user submitted a login form and both fields contain data.

Uses the cflogin structure’s name and password entries to find the user record in the database and get the user’s roles.

<cfif loginQuery.Roles NEQ ""> 
    <cfloginuser name="#cflogin.name#" Password = "#cflogin.password#" roles="#loginQuery.Roles#">

If the query returns data in the Roles field, logs in the user using the user’s name and password and the Roles field from the database. In this application, every user must be in some role.

<cfelse> 
    <cfoutput> 
    <H2>Your login information is not valid.<br> 
        Please Try again</H2> 
    </cfoutput>     
    <cfinclude template="loginform.cfm"> 
    <cfabort>

Runs if the query did not return a role. If the database is valid, this means there was no entry matching the user ID and password. Displays a message, followed by the login form.

The cfabort tag prevents processing of any code that follows on this page.

</cfif> 
</cfif>     
</cfif> 
</cflogin>

Ends the loginquery.Roles test code.

Ends the form entry empty value test.

Ends the form entry existence test.

Ends the cflogin tag body.

<cfif GetAuthUser() NEQ ""> 
    <cfoutput> 
    <form action="securitytest.cfm" method="Post"> 
    <input type="submit" Name="Logout" value="Logout"> 
    </form> 
    </cfoutput> 
</cfif>

If a user is logged-in, displays the Logout button.

If the user clicks the button, posts the form to the application’s (theoretical) entry page, index.cfm.

Application.cfc then logs out the user and displays the login form. If the user logs in again, ColdFusion displays index.cfm.

</cffunction> 
</cfcomponent>

Ends the onRequestStart method

Ends the Application component.

Example: loginform.cfm

The loginform.cfm page consists of the following:

<H2>Please Log In</H2> 
<cfoutput> 
    <form action="#CGI.script_name#?#CGI.query_string#" method="Post"> 
        <table> 
            <tr> 
                <td>user name:</td> 
                <td><input type="text" name="j_username"></td> 
            </tr> 
            <tr> 
                <td>password:</td> 
                <td><input type="password" name="j_password"></td> 
            </tr> 
        </table> 
        <br> 
        <input type="submit" value="Log In"> 
    </form> 
</cfoutput>

Reviewing the code

The following table describes the loginform.cfm page CFML code and its function:

Code

Description

<H2>Please Log In</H2> 
<cfoutput> 
    <form action="#CGI.script_name#?#CGI.query_string#" method="Post"> 
    <table> 
    <tr> 
        <td>user name:</td> 
        <td><input type="text" name="j_username"></td> 
    </tr> 
    <tr> 
        <td>password:</td> 
        <td><input type="password" name="j_password"></td> 
    </tr> 
    </table> 
    <br> 
    <input type="submit" value="Log In"> 
    </form> 
</cfoutput>

Displays the login form.

 

Constructs the form action attribute from CGI variables, with a ? character preceding the query string variable. This technique works because loginform.cfm is accessed by a cfinclude tag on Application.cfc, so the CGI variables are those for the originally requested page.

 

The form requests a user ID and password and posts the user’s input to the page specified by the newurl variable.

Uses the field names j_username and j_password. ColdFusion automatically puts form fields with these values in the cflogin.name and cflogin.password variables inside the cflogin tag.

Example: securitytest.cfm

The securitytest.cfm page shows how any application page can use ColdFusion user authorization features. Application.cfc ensures the existence of an authenticated user before the page content appears. The securitytest.cfm page uses the IsUserInAnyRole and GetAuthUser functions to control the information that is displayed.

The securitytest.cfm page consists of the following:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
<head> 
    <title>Security test page</title> 
</head> 
 
<body> 
<cfoutput> 
    <h2>Welcome #GetAuthUser()#!</h2> 
</cfoutput> 
 
ALL Logged-in Users see this message.<br> 
<br> 
<cfscript> 
    if (IsUserInRole("Human Resources")) 
        WriteOutput("Human Resources members see this message.<br><br>"); 
    if (IsUserInRole("Documentation")) 
        WriteOutput("Documentation members see this message.<br><br>"); 
    if (IsUserInRole("Sales")) 
        WriteOutput("Sales members see this message.<br><br>"); 
    if (IsUserInRole("Manager")) 
        WriteOutput("Managers see this message.<br><br>"); 
    if (IsUserInRole("Employee")) 
        WriteOutput("Employees see this message.<br><br>"); 
    if (IsUserInRole("Contractor")) 
        WriteOutput("Contractors see this message.<br><br>"); 
</cfscript> 
 
</body> 
</html>

Reviewing the code

The following table describes the securitytest.cfm page CFML code and its function:

Code

Description

<cfoutput> 
    <h2>Welcome #GetAuthUser()#!</h2> 
</cfoutput>

Displays a welcome message that includes the user’s login ID.

ALL Logged-in Users see this message.<br> 
<br>

Displays this message in all cases. The page does not display until a user is logged in.

<cfscript> 
if (IsUserInRole("Human Resources")) 
    WriteOutput("Human Resources members see this message.<br><br>"); 
if (IsUserInRole("Documentation")) 
    WriteOutput("Documentation members see this message.<br><br>"); 
if (IsUserInRole("Sales")) 
    WriteOutput("Sales members see this message.<br><br>"); 
if (IsUserInRole("Manager")) 
    WriteOutput("Managers see this message.<br><br>"); 
if (IsUserInRole("Employee")) 
    WriteOutput("Employees see this message.<br><br>"); 
if (IsUserInRole("Contractor")) 
    WriteOutput("Contractors see this message.<br><br>"); 
</cfscript>

Tests whether the user belongs to each of the valid roles. If the user is in a role, displays a message with the role name.

Users see one message per role that they belong.