Using advanced ColdFusion component functionality

Beyond basic component functionality, ColdFusion components offer advanced functionality to streamline application development, deployment, and extensibility. The following table displays advanced component functionality:
Feature
Description
For more information
Component method security
Using the roles and access attributes of the cffunciton tag, you build component method-level security measures.
Component packages
Using component packages, you avoid possible naming conflicts with components.
Component inheritance
Using the extends attribute of the cfcomponent tag, you import another component's methods and properties.
Component introspection
Using component metadata, you can describe component functionality programmatically.

Building secure ColdFusion components

To restrict access to component methods, ColdFusion components use the following security features:

  1. Web server basic authentication

    For more information, see "Using web server authentication".

  2. Application security

    For more information, see "Using ColdFusion application security".

  3. Role-based security

    For more information, see "Using role-based security".

  4. Programmatic security

    For more information, see "Using programmatic security".

Using web server authentication

The majority of web servers allow directory access protection using basic authentication. When a client tries to access one of the resources under a protected directory and is not properly authenticated, the server automatically sends back a authentication challenge to the web browser. The web browser shows a login dialog box.

When you enter your authentication information, the web browser authenticates the information to the web server. If the authentication passes, the web browser caches the authentication data while the browser window is open and every subsequent request to the web server sends the same authentication data

ColdFusion developers can use the authentication information for ColdFusion resources, such as ColdFusion pages or components, in the appropriate application.cfm file, as the following example shows:

<cflogin>
  <cfif IsDefined( "cflogin" )>
    <cfif cflogin.name eq "admin">
      <cfset roles = "user,admin">
    <cfelse>
      <cfset roles = "user">
    </cfif>
    <cfloginuser name = "#cflogin.name#"
    password = "#cflogin.password#"
    roles = "#roles#" />
  <cfelse>
    <!--- this should never happen --->
    <h4>Authentication data is missing.</h4>
    Try to reload the page or contact the site administrator.
    <cfabort>
  </cfif>
</cflogin>

Using ColdFusion application security

You can use the previous example with minor modification to include the login challenge in the application.cfm file as well. You can create an HTML form page that passes authentication information to ColdFusion, or you can return the access-denied 401 information back to the web browser.

The following example shows an authentication challenge by generating and HTML page with a login form. The login form sends two form fields, j_username and j_password, to ColdFusion, which are automatically detected by the cflogin tag.

<cflogin>
  <cfif IsDefined( "cflogin" )>
    <cfif cflogin.name eq "admin" and cflogin.password eq "p1">
      <cfset roles = "user,admin">
      <cfelseif cflogin.name eq "user" and cflogin.password eq "p2">
      <cfset roles = "user">
    </cfif>
  </cfif>
  <cfif IsDefined( "roles" )>
    <cfloginuser name="#cflogin.name#" 
      password="#cflogin.password#"
      roles="#roles#">
  <cfelse>
    <!--- authentication failed - generate the login form --->
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html><head><title>Application Log In</title></head>
    <body>
      <form action="" method="post">
        <pre>
          username: <input type="text" name="j_username">
          password: <input type="password" name="j_password">
          <input type="submit" value="log in">
        </pre>
      </form>
    </body>
    </html>
    <cfabort>
  </cfif>
</cflogin>

When you return a 401 access denied response, the browser automatically displays a login dialog box. When the user enters his or her login dialog, the authentication parameters are passed in the request header and are detected by the cflogin tag, as shown in the following example:

<cflogin>
  <cfif IsDefined( "cflogin" )>
    <cfif cflogin.name eq "admin" and cflogin.password eq "p1">
      <cfset roles = "user,admin">
    <cfelseif cflogin.name eq "user" and cflogin.password eq "p2">
      <cfset roles = "user">
    </cfif>
  </cfif>
  <cfif IsDefined( "roles" )>
    <cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="#roles#">
  <cfelse>
    <!--- authentication failed - send back 401 --->
    <cfsetting enablecfoutputonly="yes" showdebugoutput="no">
    <cfheader statuscode="401">
    <cfheader name="WWW-Authenticate" value="Basic realm=""MySecurity""">
    <cfoutput>Not authorized</cfoutput>
    <cfabort>
  </cfif>
</cflogin>

The security realm name can be used to bind multiple directories together. If Application.cfm files located in those directories use the same realm name, only a single login is required to access resources in those directories. However, each Application.cfm file can establish different roles for a user.

Using role-based security

Access to a particular method in component can be restricted using roles security. When a component method is restricted to one or more roles using the roles attribute of the cffunction tag, users must fall into one of the security roles, as shown in the following example:

<cffunction name="foo" roles="admin,moderator">
  . . .
</cffunction>

Use the cfloginuser tag to establish the security roles. The cflogin tag caches the authentication information.When a user tries to invoke a method that he or she is not authorized to invoke, an exception is returned. For more information, see Chapter 16, "Securing Applications".

Using programmatic security

In the component method definition, you can protect resources using the same CFML constructs as ColdFusion pages. For example, the IsUserInRole function determines whether the user is authenticated in a particular security role:

<cffunction name="foo">
  <cfif IsUserInRole("admin")>
    ... do stuff allowed for admin
  <cfelseif IsUserInRole("user")>
    ... do stuff allowed for user
  <cfelse>
    <cfoutput>unauthorized access</cfoutput>
    <cfabort>
  </cfif>
</cffunction>

Using component packages

Components invoked by ColdFusion pages do not need to be in the same directory as the client ColdFusion page or component, web page, or Macromedia Flash movie. In fact, components can reside in any folder under the web root directory or virtual directory mapping in the web server, in a directory under a ColdFusion mapping, or the custom tag roots.

Components stored in the same directory are members of a component package. Component packages help prevent naming conflicts and facilitate easy component deployment.

To invoke a packaged component method using the cfinvoke tag:

  1. In your web root directory, create a folder named appResources.
  2. In the appResources directory, create a folder named components.
  3. Move tellTime.cfc and utcTimeFormatted.cfm to the components directory.
  4. Create a new ColdFusion page and save it in your web root as timeDisplay.cfm.
  5. Modify the page so that is appears as follows:
    <h3>Time Display Page</h3>
    <b>Server's Local Time:</b>
    <cfinvoke component="appResources.components.tellTime"
    method="getLocalTime"><br>
    <b>Calculated UTC Time:</b>
    <cfinvoke component="appResources.components.tellTime"
    method="getUTCTime">
    

    You use dot syntax to navigate directory structures. Prefix the directory name before the component name.

  6. Save your work.

The following example shows a CFScript invocation:

<cfscript>
helloCFC = createObject("component", "appResources.components.catQuery");
helloCFC.getSaleItems();
</cfscript>

The following example shows an URL invocation:

http://localhost/appResources/components/catQuery.cfc?method=getSalesItems

Saving ColdFusion components

The following table contains the locations in which you can save component files and the available accessibility options from each location:


Web root
ColdFusion
mappings
Custom
tag roots
Current
directory
URL
Yes
Yes
No
Yes
Form
Yes
No
No
Yes
Flash Remoting
Yes
No
No
Yes
Web services
Yes
No
No
Yes
Local
Yes
Yes
Yes
Yes

Note:   ColdFusion mappings and custom tag roots can exist within the web root. If so, they are accessible to remote requests, including URL, form, Flash Remoting, and web service invocation.

Naming ColdFusion components

Establishing a descriptive naming convention is a good practice, especially if the components will be installed as a part of packaged application. Like the common Java naming convention, you can reserve the order of your domain name, continue with application name, and so on, as the following example shows:

com.mycompany.catalog.product.saw

When you refer to a component using the fully qualified name, ColdFusion looks for the component in the following order:

When a component is invoked using any of the interfaces mentioned previously, ColdFusion generates the key name in the component metadata structure in the following order:

Using component inheritance

Component inheritance lets you import component methods and properties from one component into another component. In addition, inherited components also share any component methods or properties that they inherit from other components.

When using component inheritance, inheritance should define an is a relationship between components. For example, a component named president.cfc inherits the component methods of manager.cfm, which inherits its methods from employee.cfc. In other words, president.cfc is a manager.cfc. The manager.cfc is a employee.cfc. In turn, president.cfc is a employee.cfc

To use component inheritance:

  1. Open the corpQuery.cfc file, and modify the code so that it appears as follows:
    <cfcomponent extends="appResources.components.tellTime">
      <cffunction name="getEmp" returnType="query">
      <cfargument name="lastName" required="yes">   
         <cfquery name="empQuery" datasource="ExampleApps" dbtype="ODBC">
           SELECT LASTNAME, FIRSTNAME, EMAIL
           FROM tblEmployees
          WHERE LASTNAME LIKE '#arguments.lastName#'
         </cfquery>
         <cfif empQuery.recordcount LT 1>
           <cfthrow type="noQueryResult" 
            message="No results were found. Please try again.">
          <cfelse>
              <cfreturn empQuery>
          </cfif>
      </cffunction>
      <cffunction name="getCat" returnType="query"> 
        <cfquery name="catQuery" datasource="ExampleApps" dbtype="ODBC">
           SELECT ItemName, ItemDescription, ItemCost
           FROM tblItems
         </cfquery>
         <cfif #getCat.recordcount# LT 1>
           <cfthrow type="noQueryResult"
            message="No results were found. Please try again.">
         <cfelse>
           <cfreturn catQuery>
         </cfif>
      </cffunction>
    </cfcomponent>
    

    In the example, the cfcomponent tag's extends attribute points to the tellTime component.

  2. Save your work.
  3. Create a new ColdFusion page, and save it as inherit.cfm in your web-root directory.
  4. Modify the code in the inherit.cfm file so that it appears as follows:
    <cfinvoke component="corpQuery" method="getEmp" lastName="gilson">
    <cfinvoke component="corpQuery" method="getLocalTime">
    
  5. Save your work.

When you execute the inherit.cfm file, the getLocalTime component method executes like the getEmp component method.

Using component metadata

When you access a ColdFusion component directly with a web browser without specifying a component method, the following chain of events occurs:

The following figure shows the HTML description for the corpQuery component:

HTML description of corpQuery.cfc

The description that displays in the web browser, components list the methods that you build. Development teams can use a component's automatically generated description as always up-to-date API reference information.

In addition, you can use the cfcToMCDL and cfcToHTML component methods of utils.cfc, which is located in the [webroot]\CFIDE\componentutils directory.

You can also browse the components available in ColdFusion using the Component Browser, which is located at [webroot]\CFIDE\componentutils\componentdoc.cfm.

The following figure shows the Component browser:

Component Browser

Note:   To access the Component Browser in a virtual directory, you must add the virtual directory to the ColdFusion mappings.

Comments