<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http-policy="http://www.mulesoft.org/schema/mule/http-policy">
<http-policy:proxy name="policy-template"> (1)
<http-policy:source> (2)
… (3)
<http-policy:execute-next/> (4)
… (5)
</http-policy:source>
</http-policy:proxy>
</mule>
Custom Policy Development Reference
The Mule 4 engine is more powerful than the Mule 3 engine when building custom policies due to the heavy use of Mule 4’s architecture and XML schema language.
We use Maven to build and deploy Mule 4 policies. Policies consist of two files:
-
A deployable JAR file that contains the policy implementation.
-
A YAML Configuration File, where the policy parameters and metadata are defined.
To package a policy in Maven, the development project must be composed of the following files
-
An XML template
It contains the implementation of the policy using Mule’s XML schema language.
-
A YAML file
It defines the configurable parameters of the policy. Anypoint API Manager uses this file to render the UI to display inputs for the policy.
-
The template’s
pom.xml
fileIt defines policy dependencies. The packaging type needs to be
mule-policy
. Thepom.xml
file may define any other Maven plugin that helps to manage the development lifecycle of the Maven project. -
Resources
Optional files that the policy depends on, such as certificates and configuration properties files.
-
The mule-artifact.json descriptor
Policies cannot export resources nor packages such as Java classes.
Basic XML structure
Below is an example of the basic structure of a policy configuration:
1 | The definition of a policy starts with the http-policy:proxy element with a name argument.
The http-policy:proxy element must contain http-policy:source or a http-policy:operation element.
In this example, http-policy:source is used. |
2 | The http-policy:source block contains the actual instructions to execute, relative to the Mule flow the policy is configured to handle. The http-policy:source block can inject instructions before an HTTP Listener event fires at the start
of a flow, and inject instructions after the flow completes. |
3 | Any Mule Event operation that is defined before the execute-next element will be executed before the start of a
flow with an HTTP Listener. |
4 | The http-policy:execute-next element is required to continue the Mule Event processing. The http-policy:execute-next element can trigger other policies or the application flow. Any policy can stop the Mule Event processing chain by not
executing http-policy:execute-next . |
5 | Mule Event operations defined after the http-policy:execute-next element will be executed after the flow completes.
These Mule Event processors will be able to process the Mule Event returned from the flow. |
Understanding execution order
Consider the case where a Mule application contains two policies, A and B.
Policy A has order 1 and Policy B has order 2.
Policy A is defined by the following configuration:
<http-policy:proxy name="policy-A">
<http-policy:source>
<A1 />
<http-policy:execute-next/>
<A2 />
</http-policy:source>
</http-policy:proxy>
And policy B config is:
<http-policy:proxy name="policy-B">
<http-policy:source>
<B1 />
<http-policy:execute-next/>
<B2 />
</http-policy:source>
</http-policy:proxy>
A flow is defined as:
<flow name="flow">
<http:listener />
<F1/>
</flow>
When an HTTP Request arrives at the Mule application’s endpoint, the execution order follows the diagram below:
<A1> → <B1> → <F1> → <B2> → <A2>
The policy with the lower order executes first. The flow will always execute in the middle of the policy operations.
With this model, the Mule Event processing chain can be controlled with the presence or absence of the http-policy:execute-next
element.
For example, by placing the http-policy:execute-next
element inside a choice
element, the next Mule Event execution can continue or stop, depending on the choice condition.
In the example below, the flow will only execute when the incoming request has a header named myHeader
and
its value is someValue
. A message is logged if the incoming request does not satisfy the constraint.
<http-policy:proxy name="policy">
<http-policy:source>
<choice>
<when expression="#[attributes.headers['myHeader'] == 'someValue']" >
<http-policy:execute-next/>
</when>
<otherwise>
<logger message="Avoid Flow execution" />
</otherwise>
</choice>
</http-policy:source>
</http-policy:proxy>
Using extensions
Policies, just like Mule applications, can make use of Mule extensions or plugins to extend the Mule Core capabilities.
For example, a policy is required to add additional headers to the HTTP Response from a flow’s HTTP Listener.
The first step is to add a Maven dependency that can modify an HTTP Request object.
The mule-http-policy-transform-extension
Mule plugin can modify HTTP Requests.
<dependencies>
<dependency>
<groupId>com.mulesoft.anypoint</groupId>
<artifactId>mule-http-policy-transform-extension</artifactId>
<version>1.0.0</version>
<classifier>mule-plugin</classifier>
</dependency>
</dependencies>
These examples are developed using Mule extension v1.0.0. Using a different version of the extension might cause the examples to not work as expected. To update your Mule extension version, see HTTP Policy Transform Extension.
Next, the XML http-transform
namespace must be added to expose the operations in the above dependency.
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http-policy="http://www.mulesoft.org/schema/mule/http-policy"
xmlns:http-transform="http://www.mulesoft.org/schema/mule/http-policy-transform"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http-policy http://www.mulesoft.org/schema/mule/http-policy/current/mule-http-policy.xsd
http://www.mulesoft.org/schema/mule/http-policy-transform http://www.mulesoft.org/schema/mule/http-policy-transform/current/mule-http-policy-transform.xsd">
<http-policy:proxy name="policy">
<http-policy:source>
<http-policy:execute-next/>
<http-transform:add-headers outputType="response">
<http-transform:headers>#[{'policyHeader': 'policyHeaderValue'}]</http-transform:headers>
</http-transform:add-headers>
</http-policy:source>
</http-policy:proxy>
</mule>
If a policy needs to use custom code, the policy can either:
-
Import a custom Mule plugin programmed with the Java or XML SDK Extension
-
Use the
<scripting:execute>
element to add in custom scripts
The recommended method is to use the SDK Extensions.
Custom policies can’t use connectors that export resources or packages such as Java classes. For example, custom policies can’t use the Java or Spring connectors. |
Outbound policies
Policies can be applied to outbound HTTP Requests within a flow as well. This capability enables policies to inject additional headers and other information into outbound HTTP traffic through an HTTP Requester defined in a flow.
Below is an example of a policy that contains source and operation blocks:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http-policy="http://www.mulesoft.org/schema/mule/http-policy">
<http-policy:proxy name="policy-template"> (1)
<http-policy:source>
…
<http-policy:execute-next/>
…
</http-policy:operation> (2)
</http-policy:proxy>
</mule>
1 | One http-policy:proxy element is used for both types of policy blocks. Both source and operation blocks may be present.
When both blocks are present, each block can share variables to keep state throughout the policy execution. |
2 | This policy block contains code to be executed after the flow’s HTTP Requester returns an HTTP response. If the flow does not contain an HTTP Requester element, then this block is never executed. |
In general, the http-policy:operation
block allows a policy to inject code before Mule execution reaches an HTTP Requester
and after an HTTP Requester returns an HTTP response.
The operation block can contain an http-policy:execute-next
element to control operations before and after an HTTP Request in a flow.
Execution order example
There are two policies, A and B.
Policy A has order 1 and Policy B has order 2.
Policy A is defined by the following configuration:
<http-policy:proxy name="policy-A">
<http-policy:source>
<A1 />
<http-policy:execute-next/>
<A2 />
</http-policy:source>
<http-policy:operation>
<A3 />
<http-policy:execute-next/>
<A4 />
</http-policy:operation>
</http-policy:proxy>
And policy B config is:
<http-policy:proxy name="policy-B">
<http-policy:source>
<B1 />
<http-policy:execute-next/>
<B2 />
</http-policy:source>
<http-policy:operation>
<B3 />
<http-policy:execute-next/>
<B4 />
</http-policy:operation>
</http-policy:proxy>
A flow is defined as:
<flow name="flow">
<http:listener />
<F1/>
<http:request />
<F2/>
</flow>
When Mule runtime receives an HTTP Request, the execution order is as shown in this diagram:
<A1> → <B1> → <F1> → <A3> → <B3> → <http:requester> → <B4> → <A4> → <F2> → <B2> → <A2>
Operation policies are only injected around the http:request
operation.
Error Handling
Mule 4 policies can handle errors thrown by
-
The policy
-
A flow within the Mule application
-
Other policies
Error handling can be accomplished using Mule 4’s try
and error-handler
elements.
Once an error is caught by an error-handler
, the error is either, propagated up the Mule Event processing chain, or handled, where normal Mule event process execution continues.
For example, consider the following policy and flow:
<http-policy:proxy name="policy">
<http-policy:source>
<try>
<P1 />
<http-policy:execute-next/>
<P2 />
<error-handler>
<on-error-continue>
<PEH />
</on-error-continue>
</error-handler>
</try>
</http-policy:source>
</http-policy:proxy>
<flow name="flow">
<http:listener />
<F1 />
<F2 />
<error-handler>
<on-error-continue>
<FEH />
</on-error-continue>
</error-handler>
</flow>
Scenario 1
Assume <F1>
raises an error. The execution order follows the diagram below:
<P1> → <F1> → <FEH> → <P2>
<F2>
is not executed, and processing continues into the flow’s error-handler.
Since the flow’s error-handler is configured not to propagate errors, <FEH>
will return to the policy and <P2>
executes instead of the policy’s error-handler
.
Scenario 2
Assume <P1>
raises an error. The execution order follows the diagram below:
<P1> → <PEH>
From the example above, the flow never executes.
Scenario 3
Assume now that the flow’s error handler propagates errors.
<error-handler>
<on-error-propagate>
<FEH />
</on-error-propagate>
</error-handler>
Assume <F1>
raises an error. The execution order follows the diagram below:
<P1> → <F1> → <FEH> → <PEH>
The error gets propagated back to the policy, and the policy’s error handler continues handling the error.
In summary, error handlers provide an alternative method to conditionally execute a flow within a policy.
Classloading isolation
Between policies
Policies contain the same classloading isolation architecture seen in Mule 4 applications: any resource or library that a policy defines is not visible to other policies.
Between a Policy and an Application
Classloading between policies and Mule 4 applications is not completely isolated. This scenario is similar to classloading isolation between applications and domains:
Any plugin, library, or resource visible to the application is also visible to any policy applied to that application.
However, any plugin, library, or resource visible to a policy is not visible to the application applied.
Dependency resolution
If a policy and an application use different versions of the same dependency, the application’s dependency version will be used by the policy.
You can read more on classloading isolation in the Classloading Isolation topic.
Variables and Event Scope
A policy can define any number of variables. Variables within a policy scope can be shared between policy blocks.
For example, a variable maxCount
defined in a http-policy:source
block is available in a subsequent http-policy:operation
block.
However, any variables defined in a policy are not available to other policies and to the application.
Furthermore, variables defined by the application are not available to any policy.
Mule message propagation in source policies
Policies can make changes to the Mule message, but the changes may not get propagated, depending on where the Mule message changes are made relative to the http-policy:execute-next
element.
For source policies, any modification to a Mule Message made after the http-policy:execute-next
element, will
continue propagation throughout the rest of the Mule event processing chain.
The below policy and flow illustrates this concept:
<http-policy:proxy name="policy">
<http-policy:source>
<http-policy:execute-next/>
<set-payload value="Policy Message" />
</http-policy:source>
</http-policy:proxy>
<flow name="flow">
<http:listener />
<set-payload value="Flow Message" />
</flow>
The final response back to the client will be an HTTP Response that contains "Policy Message" as the body.
However, modifications made before the execute-next
element, are not propagated to the next policy or application
by default.
Consider the below policy and flow:
<http-policy:proxy name="policy">
<http-policy:source>
<set-payload value="Policy Message" />
<http-policy:execute-next/>
</http-policy:source>
</http-policy:proxy>
<flow name="flow">
<http:listener />
<logger message=#[payload] />
</flow>
The final response back to the client will be an HTTP Response that contains an empty body. Furthermore, the logger in the flow will log an empty payload.
Propagating the Mule message
Within the http-policy:source
tag, set the attribute propagateMessageTransformations
to true
to enable propagation.
<http-policy:proxy name="policy">
<http-policy:source propagateMessageTransformations="true">
<set-payload value="Policy Message" />
<http-policy:execute-next/>
</http-policy:source>
</http-policy:proxy>
<flow name="flow">
<http:listener />
<logger message=#[payload] />
</flow>
The final response back to the client will be an HTTP Response that contains "Policy Message" as the body. The logger within the flow will log "Policy Message."
This design prevents unintentional modifications that can affect the application.
Mule message propagation in operation policies
Mule message propagation is similar to source policies but in the opposite direction. In operation policies, modifications
made before the execute-next
element are always propagated. Modifications made after the execute-next
element, are not propagated by default.
Propagation can be enabled using the same attribute propagateMessageTransformations
in the operation policy definition:
<http-policy:proxy name="scope-payload">
<http-policy:operation propagateMessageTransformations="true">
…
<http-policy:execute-next/>
…
</http-policy:operation>
</http-policy:proxy>
In summary, variables cannot be used to share information from a policy to other policies or Mule applications.
However, Mule messages can be used to share information from a policy to other policies or Mule applications.
Dependent on where the Mule message is set within a policy block, the attribute propagateMessageTransformations
may need to be set to true to enable Mule message propagation.
Authentication (Security Context)
User authentication can be exposed through the Authentication object within the Security context object.
If a policy sets the Authentication object, it will be available to other policies and to the application.
The Authentication object can be accessed using DataWeave:
#[authentication.principal] #[authentication.password] #[authentication.properties.someProperty]
The only method to set the Authentication object is through a dependency using the SDK Mule extension.
Refer to the Authentication Handler article to learn how to set the authentication object.
Mule 4 Provided Policies use this exact method to propagate client information.
YAML Configuration File
Mule 4’s policies use YAML files to store metadata and user parameters. This flexible design allows a policy to work across multiple APIs that require different user parameters and configurations.
For example, the Rate Limit Policy allows for different configurations based on user parameters: a user may want to allow up to 100 requests per minute on one API, and allow 5000 per minute on a different API.
To allow user parameters, policy developers define user input in the YAML Configuration file. The file is then used by API Manager to render the UI for user input.
Example of a Client ID enforcement YAML file
id: openam-access-token-enforcement (1)
name: OpenAM access token enforcement (2)
supportedPoliciesVersions: '>=v4' (3)
description: Enforces access tokens by OpenAM. (4)
category: Security (5)
violationCategory: authentication (6)
type: system (7)
resourceLevelSupported: true (8)
standalone: true (9)
identityManagement: (10)
type: OpenAM
- OAuth 2.0 protected
configuration: (11)
- propertyName: scopes
name: Scopes
description: A space-separated list of supported scopes
type: string
optional: true
sensitive: false
allowMultiple: false
- propertyName: exposeHeaders
name: Expose Headers
description: In a proxy scenario, defines if headers should be exposed in the request to the backend. The headers that may
be sent are the user properties returned by the federation server when validating the access token with a 'X-AGW-' prefix.
type: boolean
optional: true
defaultValue: true
allowMultiple: false
1 | Unique ID within your organization of the policy. Mandatory |
2 | User friendly name that is used for displaying the policy name in API Manager’s UI. Mandatory |
3 | Deprecated property. Value should be set to ‘>=v1’ for now. Mandatory |
4 | Description of what the policy does. Also used in API Manager’s UI. Mandatory |
5 | Category to which the policy belongs. Used to group and filter policies in API Manager’s UI, any String value is valid. Mandatory |
6 | Value used by the Edge to show metrics about different types of policy violations. Mandatory |
7 | Deprecated property. Value should be set to ‘system’. Mandatory |
8 | Whether resource level pointcuts should be enabled when applying the policy. Mandatory |
9 | Deprecated property. Value should be set to ‘true’. Mandatory |
10 | Whether policy requires information about an identity management that is configured to the API’s Organization. Optional |
11 | Where the policy parameters are defined. Every parameter listed here will be rendered as an expected user input in API Manager’s UI. It expects an array of values. Mandatory |
Below is the syntax for defining the above policy’s parameters:
propertyName: scopes (1)
name: Scopes (2)
description: A space-separated list of supported scopes (3)
type: string (4)
defaultValue: some String (5)
optional: true (6)
sensitive: false (7)
allowMultiple: false (8)
1 | Internal name of the parameter. Must be unique within the policy. |
2 | User friendly name of the parameter. Used for displaying in API Manager’s UI. |
3 | Description of the parameter. Also, used for displaying in API Manager’s UI. |
4 | Type of the parameter. |
5 | Default value for the parameter. |
6 | Whether is mandatory for the user to enter this value or not. |
7 | Whether this property should be masked when entering in API Manager’s UI. |
8 | Whether multiple values should be allowed for this parameter. |
Parameter types
Depending of the type of the parameter, the UI will render a different type of input such as:
-
text boxes
-
radio buttons
-
checkboxes
Some rendered elements require additional configurations. The list of elements that require additional configurations are:
-
String: Any string expected.
-
Expression: A DataWeave expression starting with #[ and finished with ] is expected.
-
Boolean: true or false.
-
Int: A number is expected. This type requires additional properties:
minimumValue: -1 (1) maximumValue: 2147483647 (2)
1 Minimum value allowed for the parameter. 2 Maximum value allowed for the parameter. -
Radio: One value of a group of options. This type requires additional properties:
options: (1) - name: HTTP Basic Authentication Header value: httpBasicAuthenticationHeader - name: Custom Expression value: customExpression
1 List of options for the user to choose. Each option has a name for displaying in the UI and an internal value used in the policy. -
Keyvalues: Collection of Key-Value pairs.
HandleBars
Policies support Handlebars, a templating engine for resolving the configurable parameters of the policy and implementing semantic logic, such as conditionals. This is the preferred method of using user inputs in the policies.
Each policy parameter defined in a YAML Configuration file will be available as a HandleBars variable for resolving the final policy configuration.
Handlebars is an extension of Mustache, which was used in earlier versions of Mule policies. |
Depending on the parameter type defined in the YAML, the variable will be of a different HandleBars type.
String, Expression, Radio, Int, and Boolean are primitive types in HandleBars.
The primitive types can be referenced from the policy template using curly brackets:
{{{myproperty}}}
Keyvalues are complex types in HandleBars. Complex types have inner properties, and those can be referenced as follows:
{{{keyvalue.key}}} {{{keyvalue.value}}}
There are some properties that are available to use in policies without being defined in the YAML Configuration file:
-
policyId id of the policy, useful for logging or naming a policy
-
isWsdlEndpoint indicates whether the API where the policy is being applied is a WSDL API.
When an Identity Management is defined for the organization where the API is being applied, then the following properties are also available:
identityManagementTokenUrl introspection endpoint of the identity management. identityManagementClientId client Id for authenticating to the introspection endpoint. identityManagementClientSecret client secret for authenticating to the introspection endpoint.
Pointcuts
In earlier versions, the pointcut element was required to configure a custom policy. Pointcuts specified the API that the policy operates.
In Mule 4, there is no need to configure the pointcut element. Information about the API on which the custom policy operates is provided by API Manager when a policy is applied.
See offline policies for configuration guidelines when a policy is not applied online.