WCF Hooks Extensions
Version Information
| Library |
cPanel.Core.Hooks.dll |
| Status |
BETA |
| Version |
0.1 |
| Compatible Enkompass Version |
2.0 |
Contents
Introduction
The hook system allows you to receive and process messages sent to Enkompass WCF Server's API. Advanced aspects of the system can allow you to cancel or alter API call messages while they are processed.
Information provided in this document corresponds to version BETA 0.1 of the
cPanel.Core.Hooks library. Because this is beta software, we reserve the right to change the systems definition until it is no longer in beta. We will attempt to make these changes backwards-compatible; however, we cannot guarantee that changes that we make from release to release will not break some of your customizations.
Changes will be documented in
Enkompass' change log.
Configuring hooks
Hooks are an optional component of the Enkompass WCF processing architecture. To enable the hooks system, you must add a configuration file to the hooks application path.
You can find your hooks application path by looking in your server's registry:
$cPanelApplicationPath$ = HKLM:SOFTWARE\cPanel, Inc.\cPanel\ApplicationPath
Once you have this value, combine the path listed above with the following:
$cPanelApplicationPath$\Common\Hooks\HookConfiguration.config
For example:
\\fileserver\e\ApplicationPath\Common\Hooks\HookConfiguration.config
The configuration file
The
HookConfiguration.config configuration file should resemble the following:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="hookLoaderConfiguration"
type="cPanel.Core.Hooks.HookLoaderConfigurationSection,cPanel.Core.Hooks" />
</configSections>
<hookLoaderConfiguration>
<hookItems>
...
</hookItems>
</hookLoaderConfiguration>
</configuration>
You may configure a few parameters in this file.
The <hookLoaderConfiguration> tag
You can configure the following attributes of the
<hookLoaderConfiguration> tag:
| Name |
Values |
Optional |
Default |
Notes |
| debug |
true false |
yes |
false |
Enables additional logging in the message processing layers. This logging will slow down processing for WCF calls significantly. You should either not include this attribute in the configuration file or make sure to set its value to =false in most cases. You should only enable this feature when you are trying to diagnose a problem with the hooks system. |
| logAll |
true false |
yes |
false |
Enables verbose logging of unmonitored messages, including the output of their SOAP messages. Enabling this attribute may be useful to developers trying to understand the format of the action names and details of a SOAP message's header or body. |
The <hookItems> tag
The
<hookItems> tag is contained in within the
<hookLoaderConfiguration> tag. This tag contains the collection of hooks to install on the system. Each hook is added into the
<hookItems> tag using an
<add> tag like so:
<add name="UrlHooks"
type="cPanel.Core.Hooks.UrlHookBehaviour, cPanel.Core.Hooks"
externalConfigurationPath="\\10.1.15.101\e\ApplicationPath\Common\Hooks\UrlHookConfiguration.config" /> <add>
The <add> tag
You can use the
<add> tag to add a single hook behavior to the Enkompass WCF pipeline. Each behavior represents a complete and independent way that hooks are processed. This
<add> tag has the following attributes:
| Name |
Values |
Optional |
Default |
Notes |
| name |
$string |
no |
N/A |
A unique name for the hook. |
| enable |
true false |
yes |
true |
Selects whether to enable or disable the corresponding hook. |
| type |
$fully-qualified-type |
no |
N/A |
The .NET object type that implements the hook behavior. The type may be in any format recognizable the Microsoft .NET framework. For more information, review Microsoft's type documentation. |
| path |
$path |
yes |
N/A |
If provided, this parameter will load the DLL from the specified path instead of the default location. This allows you to install DLLs for hooks outside of Enkompass, but load them into the Enkompass WCF services process.
Warning:We have not yet tested this parameter. |
| externalConfigurationPath |
$path |
no |
N/A |
The full path to the configuration file for this hook behavior. |
Types of hooks
| Type |
Description |
| Filter Hooks |
A type of hook that includes a specific set of messages to be processed. |
| Broadcast Hooks |
A type of hook that processes all the messages passed through the system. |
Available Hooks
There are 2 hook behavior libraries released with this beta. They are the
CommandHook and the
UrlHook. These hooks are considered filter hooks because you must specify specific messages you want the hook to process.
Command hooks
A command hook allows you to send specific WCF messages to an executable program. This program can be any type of executable on the Enkompass server or any executable available in the same domain as the Enkompass server. For a command hook to work, the Enkompass WCF service account must be able to execute the executable file.
A sample configuration file is shown below:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="commandHookConfiguration"
type="cPanel.Core.Hooks.CommandHookConfigurationSection,cPanel.Core.Hooks" />
</configSections>
<commandHookConfiguration enable="true" >
<handledMessages>
<add name="BeforeAmIAlive"
action="http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive"
actionType="Before" command="C:\logger\log.exe" args=" -before '{0}'" />
<add name="AfterAmIAlive"
action="http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive"
actionType="After" command="C:\logger\log.exe" args=" -after '{0}'" />
</handledMessages>
</commandHookConfiguration>
</configuration>
The <commandHookConfiguration> tag
The
<commandHookConfiguration> tag has the following attributes:
| Name |
Values |
Optional |
Default |
Notes |
| enabled |
true false |
yes |
true |
Turns the entire hook behavior on or off. You must restart the WCF service for changes to this attribute to take effect. |
The <handledMessages> tag
This tag contains a list of the messages that will be processed by the command hook behavior. Each message must be specified by an
<add> tag.
The <add> tag
This tag configures the command hook for a single message. Each message you want to process should include an
<add> tag.
The
<add> tag has the following attributes:
| Name |
Values |
Optional |
Default |
Notes |
| name |
$string |
no |
N/A |
The unique name of the message to process. This is something you make up to describe the message you are processing. |
| action |
$string |
no |
N/A |
The internal representation for the WCF message you want to process. This value should be formatted like so: http://www.cpanel.net/schemas/2008/03/<ServiceInterface>/<MessageName> Where <ServiceInterface> is one of the following:
- IServerAdministratorService — Methods for SAI
- IWebSiteOwnerService — Methods for WSOI
- IMailOwnerService — Methods for MOI
The <MessageName> tag is the name of the method to call to the API. |
| actionType |
Before After |
yes |
After |
This value indicates when the hook should be used, either before or after the API call is processed.
Note: Before action types can cancel the API call; After action types cannot. |
| command |
$string |
no |
N/A |
The command to call when the message is received. The command can include optional substitution parameters using {#} syntax. The following are valid substitution parameters.
- {0} - Message Name
- {1} - Stage
|
| args |
$string |
yes |
N/A |
The arguments to pass to the command. Arguments can include optional substitution parameters using {#} syntax. The following are valid substitution parameters: |
| stripSoapEnvelope |
true false |
yes |
true |
WCF processes all messages as SOAP calls. The hook has code to strip out SOAP headers if this is attribute is set to true. When set to =false, the message is passed to the command as-is. |
| transform |
$XSLT |
yes |
N/A |
A valid XSLT transform definition to apply to the message sent to the command.
Note: If stripSoapEnvelope is enabled, the SOAP headers are stripped before this transform is called. |
The command, called by the command hook, should expect the incoming message data on standard input. It should send output to standard output and errors to standard error.
For hooks with action
Type = Before, the input message format is as follows:
Log.exe Information: 0 : [ ] 2011-06-07 17:23:45Z [INFO : ] - Command Hook Application - Main - Before 'http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive'
Message ID: f9fdae87-eb37-4a54-afa9-665691706297
Action: http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive
Stage: BeforeDispatch
Request:
<AmIAlive xmlns="http://www.cpanel.net/schemas/2008/03/" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" />
For hooks with action
Type = After, the input message format is as follows:
Log.exe Information: 0 : [ ] 2011-06-07 17:23:45Z [INFO : ] - Command Hook Application - Main - After 'http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive'
Message ID: 27d2a629-8101-4338-bc5a-202fe40ccfd6
Action: http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive
Stage: AfterDispatch
Request:
<AmIAlive xmlns="http://www.cpanel.net/schemas/2008/03/" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" />
Response:
<AmIAliveResponse xmlns="http://www.cpanel.net/schemas/2008/03/" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<AmIAliveResult>true</AmIAliveResult>
</AmIAliveResponse>
Writing a command
When designing the command to process the hooked event, the process will pass the event name on the command line.
The command should expect the following keys to identify parts of the message:
| Key |
Value |
Description |
| Message ID |
$GUID |
The unique identifier for the message in the processing chain. |
| Action |
$URL |
The unique name of the event in URL format. |
| Stage |
BeforeDispatch AfterDispatch |
Indicates whether the hook event is sent before or after the core API is called. BeforeDispatch indicates that the command can be canceled by the hook, as the the hook event is taking place before the API call. =AfterDispatch indicates that the hook is called after the core API call is run. |
| Request:/r/n |
URL-encoded XML |
The request tag is on a line by itself. The request body is on the next line and is URL-encoded. |
| Response:/rn |
URL-encoded XML |
The response tag is on a line by itself. The response body is on the next line and is URL-encoded. The response is sent only if the Stage is set to AfterDispatch. |
| /r/n/r/n |
$EOF |
Two consecutive empty lines indicate the end of the file. |
Sample log
Before http://tempuri.org/ICalculator/Divide
Message ID: edbf2452-36db-4acd-a8ad-96f9f40b30aa
Action: http://tempuri.org/ICalculator/Divide
Stage: BeforeDispatch
Request:
<Divide>
<i>6</i>
<j>9</j>
</Divide>
After http://tempuri.org/ICalculator/Divide
Message ID: fc7ac19d-5fe5-4942-b12d-360411760ea7
Action: http://tempuri.org/ICalculator/Divide
Stage: AfterDispatch
Request:
<Divide>
<i>6</i>
<j>9</j>
</Divide>
Response:
<DivideResponse>
<DivideResult>0</DivideResult>
</DivideResponse>
URL hooks
URL hooks allow you to send WCF messages to a URL to be processed. The URL should use standard HTTP requests and response mechanisms.
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="urlHookConfiguration"
type="cPanel.Core.Hooks.UrlHookConfigurationSection,cPanel.Core.Hooks" />
</configSections>
<urlHookConfiguration enable="true" baseUrl="http://10.1.15.102:2086/logmessage.aspx" >
<handledMessages>
...
</handledMessages>
</urlHookConfiguration>
</configuration>
The <urlHookConfiguration> tag
| Name |
Values |
Optional |
Default |
Notes |
| enabled |
true false |
yes |
true |
Enables or disables the hook behavior. You must restart the WCF service for this to take effect. |
| baseUrl |
$URL |
yes |
N/A |
This attribute allows you to define the message URLs as relative to the base URL. |
The <add> tag
This tag configures the URL hook for a single message. Each message you want to process should include an
<add> tag.
| Name |
Values |
Optional |
Default |
Notes |
| name |
$string |
no |
N/A |
The unique name of the message to process. This is something you make up to describe the message you are processing. |
| action |
$string |
no |
N/A |
The internal representation for the WCF message you want to process. This value should be formatted like so: http://www.cpanel.net/schemas/2008/03/<ServiceInterface>/<MessageName> Where <ServiceInterface> is one of the following:
- IServerAdministratorService — Methods for SAI
- IWebSiteOwnerService — Methods for WSOI
- IMailOwnerService — Methods for MOI
The <MessageName> tag is the name of the method to call to the API. |
| actionType |
Before After |
yes |
After |
This value indicates when the hook should be used: either before or after the API call is processed.
Note: Before action types can cancel the API call; =After action types cannot. |
| url |
$string |
no |
N/A |
The URL to call when the message is received. The URL can include optional substitution parameters using {#} syntax. The following are valid substitution parameters:
- {0} - Message Name
- {1} - Stage
|
| isRelativeUrl |
true false |
yes |
false |
If true, the URL indicated above is a relative URL and will be combined with =baseUrl above. If false, then the above URL is a fully qualified URL. |
| stripSoapEnvelope |
true false |
yes |
true |
WCF processes all messages as SOAP calls. The hook has code to strip out SOAP headers if this attribute is set to true. When set to =false, the message is passed to the command as-is. |
| transform |
$XSLT |
yes |
N/A |
A valid XSLT transform definition to apply to the message sent to the command.
Note: If stripSoapEnvelope is enabled, the SOAP headers are stripped before this transform is called. |
The URL called by the command hook should expect incoming message data as part of the HTTP request body and should return data via the HTTP response body.
For hooks with
actionType = Before, the input message format is as follows:
cPanel.Web Information: 0 : [ ] 2011-06-07 17:43:06Z [INFO : ] - Test - LogMessage - http://10.1.15.102:2086/logger/logmessage.aspx?action=Before&message=http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive
cPanel.Web Information: 0 : [ ] 2011-06-07 17:43:06Z [INFO : ] - Test - LogMessage - Message ID: dd26771a-63f1-4e3c-bd89-0ab38310c21a
Action: http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive
Stage: BeforeDispatch
Request:
<AmIAlive xmlns="http://www.cpanel.net/schemas/2008/03/" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" />
For hooks with
actionType = After, the input message format is as follows:
cPanel.Web Information: 0 : [ ] 2011-06-07 17:43:06Z [INFO : ] - Test - LogMessage - http://10.1.15.102:2086/logger/logmessage.aspx?stage=After&message=http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive
cPanel.Web Information: 0 : [ ] 2011-06-07 17:43:06Z [INFO : ] - Test - LogMessage - Message ID: b2cf36ce-8e6c-4b71-981a-f4faeed51f52
Action: http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive
Stage: AfterDispatch
Request:
<AmIAlive xmlns="http://www.cpanel.net/schemas/2008/03/" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" />
Response:
<AmIAliveResponse xmlns="http://www.cpanel.net/schemas/2008/03/" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<AmIAliveResult>true</AmIAliveResult>
</AmIAliveResponse>
The URL hook should return one of the following HTTP status codes. You may use some of these codes to modify the message's processing cycle.
| HTTP Status |
Code |
Cancels Operation |
| Ok |
200 |
No |
| Created |
201 |
No |
| Accepted |
202 |
No |
| Unauthorized |
402 |
Yes* |
| Forbidden |
403 |
Yes* |
Note: Canceling only occurs if the hook took place before the API function was called.
Hook configuration samples
The following is an example of
HookConfiguration.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="hookLoaderConfiguration" type="cPanel.Core.Hooks.HookLoaderConfigurationSection,cPanel.Core.Hooks" />
</configSections>
<hookLoaderConfiguration debug="true">
<hookItems>
<add name="UrlHooks" type="cPanel.Core.Hooks.UrlHookBehaviour, cPanel.Core.Hooks"
externalConfigurationPath="\\10.1.15.101\e\ApplicationPath\Common\Hooks\UrlHookConfiguration.config" />
<add name="CommandHooks" type="cPanel.Core.Hooks.CommandHookBehaviour, cPanel.Core.Hooks"
externalConfigurationPath="\\10.1.15.101\e\ApplicationPath\Common\Hooks\CommandHookConfiguration.config" />
</hookItems>
</hookLoaderConfiguration>
</configuration>
The following is an example of CommandHookConfiguration.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="commandHookConfiguration" type="cPanel.Core.Hooks.CommandHookConfigurationSection,cPanel.Core.Hooks" />
</configSections>
<commandHookConfiguration enable="true" >
<handledMessages>
<add name="BeforeAmIAlive"
action="http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive"
actionType="Before" command="C:\logger\log.exe" args=" -before '{0}'" />
<add name="AfterAmIAlive"
action="http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive"
actionType="After" command="C:\logger\log.exe" args=" -after '{0}'" />
</handledMessages>
</commandHookConfiguration>
</configuration>
The following zip files are examples for TestCommand and CommandHook:
The following is an example of UrlHookConfiguration.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="urlHookConfiguration" type="cPanel.Core.Hooks.UrlHookConfigurationSection,cPanel.Core.Hooks" />
</configSections>
<urlHookConfiguration enable="true" baseUrl="http://10.1.15.102:2086/logmessage.aspx" >
<handledMessages>
<add name="BeforeAmIAlive"
action="http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive"
actionType="Before" url="?action=Before&message={0}" isRelativeUrl="true" />
<add name="AfterAmIAlive"
action="http://www.cpanel.net/schemas/2008/03/IServerAdministratorService/AmIAlive"
actionType="After" url="?stage=After&message={0}" isRelativeUrl="true" />
</handledMessages>
</urlHookConfiguration>
</configuration>
The following zip file is an example of a test page for UrlHook:
To make the logger above record information to your SAI log file, you must change system.diagnostics in your SAI web.config to:
<system.diagnostics>
<trace autoflush="true" indentsize="4" />
<sources>
<source name="cPanel.Web" switchValue="Verbose">
<listeners>
<add name="textListener"/>
</listeners>
</source>
<source name="cPanel.Web.Build" switchValue="Error">
<listeners>
<add name="textBuildListener"/>
</listeners>
</source>
</sources>
<switches>
<add name="cPanel.EntryType" value="All"/>
</switches>
<sharedListeners>
<add type="System.Diagnostics.ConsoleTraceListener"
name="consoleListener"
traceOutputOptions="None"/>
<add type="cPanel.Web.Logging.RollingTextWriterTraceListener, cPanel.Web.Logging, Culture=neutral"
initializeData="fsailog.txt"
name="textListener"
traceOutputOptions="None"/>
<add type="cPanel.Web.Logging.RollingTextWriterTraceListener, cPanel.Web.Logging, Culture=neutral"
initializeData="fbsailog.txt"
name="textBuildListener"
traceOutputOptions="None"/>
</sharedListeners>
</system.diagnostics>
Extending hooks
The command and URL hooks classes were designed to allow developers to extend functionality to support the integration scenario beyond our current implementation. There are many extension points in both of these classes.
Command Hook Classes
The command hook contains three main groups of classes:

The CommandHook class summary
The first class is the CommandHook class, which is derived from the hook class:

The CommandHook class
The command hook, as described above, provides a way to map a message received by the WCF API to an external, executable command. Out of the box, this class comes with fairly limited command and argument formatting. However, the FormatCommand() and FormatArguments() methods are virtual methods. This means that if the services provided by the class are inadequate, you can create your own CommandHook-derived class as seen below.
Additionally, if you do not like the current way the command hook writes messages to the input stream or processes the command response, you can override WriteMessage() or ProcessCommandResponse(). A sample custom implementation is shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cPanel.Core.Hooks;
namespace Sample
{
public class CustomCommandHook : CommandHook
{
protected override string FormatCommand(string command, HookExtension call, Stage stage, CommandHookMessage config)
{
// Do what you want here to create the command call string
return base.FormatCommand(command, call, stage, config);
}
protected override string FormatArguments(string arguments, HookExtension call, Stage stage, CommandHookMessage config)
{
// Do what you want here to create the command arguments string
return base.FormatArguments(arguments, call, stage, config);
}
}
}
If you create a custom implementation class, you must also create a set of installer classes for the new CustomCommandHook. Standard installers are defined in the CommandHookOperationBehaviorAttribute and CommandHookBehavior classes.
To implement your own custom versions of these classes, you can use the generic installer types like so:
public class CustomCommandHookBehavior : HookBehaviour<CustomCommandHook>
{
}
public class CustomCOmmandHookBehaviorAttribute : HookOperationBehaviorAttribute<CustomCommandHook>
{
}
With these three classes, you have a complete extension solution for the command hook. You can now add your custom hooks to your $cPanelApplicationPath$\Common\Hooks\HookConfiguration.config file, as you did with the hooks that we provided.
<add name="CustomCommandHooks" type="Sample.UrlHookBehaviour, Sample" externalConfigurationPath="\\10.1.15.101\e\ApplicationPath\Common\Hooks\CommandHookConfiguration.config" />