Beyond basic component functionality, ColdFusion components offer advanced functionality to streamline application development, deployment, and extensibility. The following table displays advanced component functionality:
To restrict access to component methods, ColdFusion components use the following security features:
For more information, see "Using web server authentication".
For more information, see "Using ColdFusion application security".
For more information, see "Using role-based security".
For more information, see "Using programmatic security".
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>
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.
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".
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>
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.
<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.
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
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.
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:
GetRealPath
function to evaluate the component physical path. The URI path string after .cfc and the leading slash is removed, and all slashes are replaced with dots.
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
<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.
<cfinvoke component="corpQuery" method="getEmp" lastName="gilson"> <cfinvoke component="corpQuery" method="getLocalTime">
When you execute the inherit.cfm file, the getLocalTime
component method executes like the getEmp
component method.
When you access a ColdFusion component directly with a web browser without specifying a component method, the following chain of events occurs:
corpQuery
component is accessed directly by a web browser, it produces the following results:The following figure shows the HTML description for the corpQuery component:
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:
Note: To access the Component Browser in a virtual directory, you must add the virtual directory to the ColdFusion mappings.