-
Notifications
You must be signed in to change notification settings - Fork 24
Removing Event Handlers for Security Reasons
Sometimes in your application you might create event-handlers that are used during development, but should not be available when your application is deployed to a production environment. Such events are commonly used to test pages, as development utilities, or as database quick view pages which do not have any security measures in place.
The simplest solution is to manually delete these event-handlers from your XML configuration file before deploying your application to your production environment, however this is an error prone and messy process. In this wiki entry, we will explore a programmatic solution that will remove the event-handlers you define using the Mach-II API, the [Simple Pattern Matcher][MachII18SpecificationToolkitEnhancements_SimplePatternMatchingwithSimplePatternMatcher.cfc] utility included in Mach-II 1.8+, the Environment Property included in Mach-II 1.8+, and a plugin we will write.
Instead of manually commenting out the event-handlers we do not want to deploy to production, we are going to remove them programmatically from the Mach-II EventManager
when the application is run on production. We're making full use of the EnvironmentProperty
that is bundled with Mach-II 1.8+ so you may want to read that documentation before continuing here.
Another consideration is that in certain applications you may have many event-handlers to remove. Instead of listing each event-handler by name, we are going to use the Mach-II SimplePatternMatcher
CFC which allows us to use the RegEx like wildcard character *
(asterisk or star). If you've used a convention when naming your event-handlers, like test.this
or test.that
-- you can use a pattern like test.*
to easily remove those events.
Lastly, we are going the use the API available to us in the EventManager
to remove an event-handler from the application when Mach-II is loading the framework.
The example in this article shows the usage of a plugin to remove the event-handlers, but you could use a Property CFC as well if you prefer.
Below is a plugin that we've defined in the XML configuration file. Notice that we are using an array of event-handler patterns that we want to remove when Mach-II is loaded. For example, the pattern preview.*
will match any event-handler name that starts with preview.
and due to the *
wildcard -- any additional characters. Of course these are just examples, so you'll need to change the patterns to match the naming conventions used in your application.
<plugin name="application" type="MyApplication.plugins.ApplicationPlugin">
<parameters>
<parameter name="removeEventHandlersOnProduction">
<array>
<element value="preview.*"/>
<element value="test.*"/>
</array>
</parameter>
</parameters>
</plugin>
Honestly, the code behind all of this is rather simple and straightforward. We only want to remove the event-handlers that match the patterns on our production
environment group, so this code will only run if the application is deployed on a production environment as defined by the EnvironmentProperty
.
If you don't have any environments setup, this code will run because the default environment group is production
if you are not using the EnvironmentProperty
. Setting up environments is a snap with the EnvironmentProperty
so, again, you may want to read that documentation before proceeding.
Another work horse in this example is the Simple Pattern Matcher which makes matches by allowing you to use a simple *
wildcard. This allows us to check our event name against an event name pattern that utilizes the *
wildcard.
<cfcomponent
displayname="ApplicationPlugin"
extends="MachII.framework.Plugin"
output="false"
hint="Performs application wide tasks.">
<!---
PROPERTIES
--->
<cfset variables.matcher = CreateObject("component", "MachII.util.SimplePatternMatcher").init() />
<!---
INITIALIZATION / CONFIGURATION
--->
<cffunction name="configure" access="public" returntype="void" output="false"
hint="Configures the plugin.">
<cfset var removeEventHandlersOnProduction = getParameter("removeEventHandlersOnProduction") />
<cfset var eventManager = getAppManager().getEventManager() />
<cfset var eventHandlerNames = eventManager.getEventNames() />
<cfset var i = 0 />
<!--- Remove events when in production environment group --->
<cfif getAppManager().getEnvironmentGroup() EQ "production">
<cfloop array="#eventHandlerNames#" index="i">
<cfif variables.matcher.match(removeEventHandlersOnProduction, i)>
<cfset eventManager.removeEvent(i) />
</cfif>
</cfloop>
</cfif>
</cffunction>
</cfcomponent>
- In the pseudo-constructor area, we are creating a simple pattern matcher object for us to use in the
configure
method. Remember, theconfigure
method is only run once during the application life cycle (when the framework loads). - In the
configure
method, we need to grab the array of patterns (or concrete event-handler names -- it is not required they are patterns). Notice that the loop will only run when the application is in a production group. If you want to remove the events in other environment groups, you'll have to modify the code. - Lastly, we are going to loop through each event-handler name and ask the simple patter match if the current event-handler name matches any of the patterns we want to remove. If one of the supplied patterns matches, then we use the
EventManager
API to remove the event-handler by passing in the event-handler name. Notice we don't even have to loop over our array of patterns. The Simple Pattern Matcher accepts a single pattern or in this case an array of patterns to check against.
Voila! It's simple as that.
As you can see, this somewhat complex task is easily accomplished using the Mach-II API, Mach-II supplied utilities, and just a few lines of code. Also, since we are using patterns, if you add another event-handler like test.thisCrazyThing
to your application, it will be removed when you deploy your application to production because you used a pattern instead of defining a concrete event-handler name.