Extension Example

Developer Documentation
 Developer Guide
Download the developer’s guide.

 Object Model Documentation
View the object model to assist in building your extension properly.

In this example we are going to create an extension that evaluates the version of Cisco devices. The logic of this extension is very basic and simple, but it allows us to focus on the framework of creating an extension and it can be used as starting point for creating any new extension.

Note: this complete extension is available here.
You must be logged in to download the extension.

1. Create Your Extension Skeleton

Every extension must consist of the same 3 files:

  • Model.xml
  • View.vm
  • Controller.js

To get started, create a directory to hold these files. There is no name requirement for this directory, but convention is to use a form of the extension name without spaces to make it easy to identify. In our case, we will create a directory called NokiaCPVersion. Inside of this directory, we will create the three files.

2. Define Your Extension

The Model.xml file contains all the key elements to define your new extension -- things like name, description, extension ID, and category, as well as all of your input properties. Below are some key elements that must be defined and an explanation of each.

Sample Model.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<AuditCheckCategoryDescriptors>
  <AuditCheckCategoryDescriptor>
    <Name>FireMon</Name>
    <AuditCheckDescriptors>
      <AuditCheckDescriptor>
        <Key>575f04b4-79c5-4f92-b9a0-cd2a3c39d4af</Key>
        <Name>Audit for Cisco Version</Name>
        <Description>Ensures Cisco devices meet minimum version criteria.</Description>
	<TargetsMustSupportNormalization>false</TargetsMustSupportNormalization>
        <Severity>0</Severity>
        <TypeKey>38088da1-0664-490a-9a3b-3e6ef6694ba6</TypeKey>        
        <HandlerTypeName>com.sp.business.compliance.auditcheckhandlers.javascript.JavascriptHandler</HandlerTypeName>
        <Script>
          <Includes>
            <Include>./conf/compliance/javascript/Common.js</Include>
          </Includes>
        </Script>
        <PropertyDescriptors>
          <PropertyDescriptor>
            <Key>pixVersion</Key>
            <Name>PIX Minimum Version</Name>
            <DataType>String</DataType>
            <DefaultValue></DefaultValue>
            <Description></Description>
          </PropertyDescriptor>
          <PropertyDescriptor>
            <Key>asaVersion</Key>
            <Name>ASA Minimum Version</Name>
            <DataType>String</DataType>
            <DefaultValue></DefaultValue>
            <Description></Description>
          </PropertyDescriptor>	  
          <PropertyDescriptor>
            <Key>iosVersion</Key>
            <Name>IOS Minimum Version</Name>
            <DataType>String</DataType>
            <DefaultValue></DefaultValue>
            <Description></Description>
          </PropertyDescriptor>
        </PropertyDescriptors>
      </AuditCheckDescriptor>
    </AuditCheckDescriptors>
  </AuditCheckCategoryDescriptor>
</AuditCheckCategoryDescriptors>

A. Define the extension:

  • <key>: The AuditCheckDescriptor key is the key that defines this extension. This must be unique. If you copy an existing extension to start building your extension, make sure to change this key. Failure to do so can result in unpredictable behavior when the system dynamically loads the extension at execution time.
  • <Name> and <Description> are just what you would guess.
  • The first <Name> above that is in the <AuditCheckCategoryDescriptor> element and is the name of the category that this extension lives in. This category will affect the organization of where you can find the extension in the FireMon Security Manager GUI. You can add a "/" to next this deeper such as "Nokia/NextLevel/AnotherLevel/AndMore".
  • <TypeKey>: This defines the extension as a standard Extension. You should not change this.
  • <HandlerTypeName>: This defines the extension as a standard Extension. You should not change this.
  • <TargetMustSupportNormalization>: Since we are going to evaluate a device (Nokia IPSO with text-based configurations), we set this to false. For firewall and policy-based analysis, this can be true.

B. Define input parameters:

  • <PropertyDescriptor>: The PropertyDescriptor defines the input parameters of a new check.
  • <Key>: The key is how you will reference the parameter in the check logic.
  • <DataType>: The DataType defines acceptable input data.

3. Create Your Extension Logic

Loading, analyzing and preparing information for output is all done in the JavaScript file, Controller.js. The controller file is typically where the majority of the logic of an extension is created. In this example, it’s pretty straightforward to load the Cisco running-config file, parse it by lines, find the version line and compare its value to the input value.

Sample Controller.js file:

// Cisco check version extension
// User input of minimum version for PIX, ASA, and IOS
// Check finds version line, parses the format (ex. 12.2(5)) to determine if that device
// meets the requirement.
// Output contains the version from the config for every device.

importPackage(java.util);
importPackage(org.apache.commons.lang);
importPackage(org.apache.commons.collections);
importPackage(com.sp.business.objectmodel);
importPackage(com.sp.business.compliance);
importPackage(com.sp.generated.xml.firemon);
importPackage(com.sp.reporting.formatters.helper)
importPackage(com.sp.reporting.formatters.view.wrapper);

// Load the application and look up the product ID and Name
var application = scriptInput.getApplication();
var productVersionKey = application.getProductVersion().getProductVersionKeyAsUUID()
var appName = application.getProductVersion().getDisplayName();

// Source allows the scritp to load the user inputs
// Logger allows us to output any data to ../firemon/JAS/firemon.log.txt
var source = scriptInput.getSource();
var logger = scriptOutput.getLogger();

// Call the main function
main();


function main() 
{

// To check the Cisco version, I want to load a text string of running-config
var fileName = 'running-config';

// Three steps to load the config into a variable.  First, getConfiguration gets
// the configuration that this check was running against.  The funtion readFile
// with the argument of the filename tells the framework that I want to load running-config.
// Finally, since the file is loaded as a single stream of characters so the first
// thing we want to do is parse the text by line breaks and have each line be a member
// of an array.
var configuration = scriptInput.getTarget().getConfiguration();
var data = readFile(fileName).getFileAsString();
var configArray = data.split('\n');

// This variable will keep the pass or fail result.
var pass = true;

// These 3 variables define the pattern for the Version line in PIX, ASA and IOS as regular
// expressions that will also parse the major.minor version and the build number.
var pixLine = /PIX\sVersion\s(?:(\d+\.\d+))\((\d+)\)/;
var asaLine = /ASA\sVersion\s(?:(\d+\.\d+))\((\d+)\)/;
var iosLine = /version\s(?:(\d+\.\d+))\((\d+)\)/;

// Loop through all lines of the configuration
for(var i=0; i<configArray.length; i++)
{
	//Test to see if the line matches the ASA pattern.  If so, record the line for the
	//output in a varialbe called lines, parse the line with the regex with exec and load
	//the ASA version from the user.  Finally, send the version from the config and the
	//version from the user to checkVersion for comparison.
	if (asaLine.test(configArray[i]))
	{
		var lines = configArray[i];
		var configVersion = asaLine.exec(configArray[i]);
		var inputVersion = source.getProperty("asaVersion"); 

		logger.info("Major/Minor: " + configVersion[1]);
		logger.info("Build: " + configVersion[2]);

		var pass = checkVersion(configVersion, inputVersion);
	}
	
	else if (pixLine.test(configArray[i]))
	{
		var lines = configArray[i];
		var configVersion = pixLine.exec(configArray[i]);
		var inputVersion = source.getProperty("pixVersion");
	
		var pass = checkVersion(configVersion, inputVersion);
	}

	else if (iosLine.test(configArray[i]))
	{
		var lines = configArray[i];
		var configVersion = iosLine.exec(configArray[i]);
		var inputVersion = source.getProperty("iosVersion");

		var pass = checkVersion(configVersion, inputVersion);
	}

}


//Prepare to send information out to the View.vm file for display.
var velocity = new VelocityHelper();
if (lines != null) velocity.getContext().put("lines", lines);
var templateFilename = source.getDescriptor().getScript().getViewFilename();
var html = velocity.merge(templateFilename);
scriptOutput.setOutput(html);

// This sets the pass/fail information for the check.  If the version is greater
// than or equal to the input mimimum version, the check will pass.  Otherwise
// it will fail.
scriptOutput.setPassed(pass);

}

// Read the running-config file from the system.
function readFile(name)
{
        try
        {
                var config = scriptInput.getTarget();
                if (config != null)
                        return config.getFileByName(name);
        }
        catch (ex)
        {
                scriptOutput.getLogger().error(ex);
        }
        return null;
}

// function checkVersion
// Input the version of a Cisco device and measure that against the user input
// minimum version.
function checkVersion(configVersion, inputVersion)
{
	var inputFormat = /(\d+\.\d+)\((\d+)\)/;
	inputVersion = inputFormat.exec(inputVersion);
	
	if (configVersion[1] > inputVersion[1])
		return true
	
	if (configVersion[1] == inputVersion[1] && configVersion[2] >= inputVersion[2])
		return true

	return false
}

4. Using Your Extension

Once your logic is complete in the Controller file, your extension is immediately available in your FireMon Security Manager application. You can run it by going to the Compliance section, selecting New > Audit Check and picking the name of your extension from the list.


5. Packaging and Publishing Your Extension

When you are finished with your extension you can share it with the rest of the community. To learn how, follow this link.