Composing Policy Logic

The Policy Manager uses a simple programming-like policy language that can create complex service policies. The composite assertions are the main entities–these let you create "AND" and "OR" constructs, using a folder metaphor that conveniently groups the relevant assertions and helps reinforce a parent/child relationship. Combine this ability with the Boolean "true/false" values returned by assertions and you can express powerful decisions.
gateway83
The Policy Manager uses a simple programming-like policy language that can create complex service policies. The 
composite assertions
 are the main entities–these let you create "AND" and "OR" constructs, using a folder metaphor that conveniently groups the relevant assertions and helps reinforce a parent/child relationship. Combine this ability with the Boolean "true/false" values returned by assertions and you can express powerful decisions.
 
 
Composite Assertions
The two main composite assertions are:
 For simplicity, the At Least One Assertion Must Evaluate to True Assertion will be the "OR assertion".
One very important point to note: these composites run their child assertions only until a  state change:
  • The "All assertions..." runs its child assertions sequentially until one fails.
  • The "At least..." runs its assertions sequentially until one succeeds.
The ordering of the child assertions matter greatly, because all assertions after the state change are 
not
 executed.
 
Best practice tips:
 Optimize the order of assertions in your policy. Since policy execution for a branch halts upon failure, put your "cheapest" or most "lightweight" assertions earlier in your policy. For example: If SSL is always required, check for it early on in your policy. Checking for SSL is very fast and it quickly discards attack attempt with non-SSL messages.
"Quick" assertions are those that simply check for the existence of certain data; examples include:
By comparison, a more complex assertion like the Apply XSL Transformation Assertion is considered "expensive" because it places greater demands on the CPU and the demand increases as the message gets larger.
Other Composite Assertions
In addition to the two main assertions listed above, these composite assertions are more esoteric variations:
Building Common Structures
IF-THEN
The IF-THEN programming structure is easily reproduced using the AND assertion. The only possible confusion point for programmers is that strictly speaking, all inputs are evaluated in a logical AND but the Gateway stops processing the AND assertion at the first failure. Because of this, the Gateway's AND assertion can be thought of a "short-circuited" AND: the first child assertion that returns false causes the entire AND assertion to return false immediately.
To reproduce the IF-THEN in a service policy, use the AND assertion with two child assertions. If the first assertion succeeds, then the second assertion is run.
Composing Policy Logic - simple
Composing Policy Logic - simple
In the Policy Manager, this IF-THEN construct looks like the following. Note that composite assertions are represented by a folder icon, which implies the child assertions are evaluated in sequence.
 IFThen2.png 
You read this policy fragment as 
"If the context variable ${thevalue} is equal to the string 'true', then attempt to route to the service located at http://backend.ca.com:8080/Example"
.
IF-THEN-ELSE
To replicate the IF-THEN-ELSE structure, embed the IF-THEN defined above within an OR assertion and then provide the alternate ELSE path:
 IFThenELSE.png 
Note the OR assertion ("At least...") is now the parent. The AND assertion ("All...") provides the IF-THEN logic. If this AND fails, the ELSE assertion (routing to "theotherbackend") is attempted. If the AND succeeds, the ELSE routing is not attempted because the OR assertion stops processing on the first successful child.
Reading the policy fragment: 
"If the context variable ${thevalue} is equal to the string 'true', then attempt to route to the "backend" service, else attempt to route to
 the "otherbackend" service."
Using formal logic gates, this construct looks like this:
 IfThenElse2.png 
Composite Assertions Ramifications
Use composite assertions with care. They are powerful tools to help you precisely control your policy, but they can potentially hide errors. Here are some examples:
  • The AND ("All...") assertion stops processing and returns false as soon as a child condition is not met. But it is not immediately clear what halted the processing: Is the comparison string not equal? Or an XPath did not find an element in the document? Or the back-end system did not acknowledge the HTTP request? Moreover, since processing is halted immediately, you will not know whether subsequent child assertions are successful. 
  • The OR ("At least...") assertion always runs the next assertion if the previous child returns false. You do not know if this false was caused by a logic check or whether the assertion returned an error. This means it is possible to have an error hidden by policy logic
Aside from hiding potential errors, it is easy to misread–or be mislead by–nested composite assertions. Here is a simple example: You have primary ("backend1") and secondary ("backend2") routing destinations. If routing to the primary fails, you want to log an audit message and then attempt the secondary path. The proper way to achieve this is with a policy fragment like the following:
 IfThenElse3.PNG 
Reading the policy fragment:
 "If the context variable ${thevalue} is equal to the string 'true', then attempt to route to the 'backend1' service. If that routing attempt fails, audit a message, and then stop and fail that sub-branch of the policy. Finally, if the previous policy sub-branch failed, attempt to route to 'backend2' service."
 
The Gateway always tracks the audit context for assertion errors, even if you don't include any auditing assertion in your policy. This means it is possible to have a service working as intended, hiding errors from users but reporting them to monitoring tools. This may be correct and desired outcome in most cases, but it can be unexpected and may cause some surprises.
The following table describes logic flow in the policy fragment, along with any ramifications.
Line
Description
1
This policy fragment is encased within an OR assertion. The two children are: the AND assertion in line 2 and the secondary routing in line 9.
2
The first child is an AND assertion. For this to succeed, both the comparison in line 3 
and
 the OR assertion in line 4 must be true. 
3
Tests the 
${thevalue}
 variable. If it is true, routing to the primary back end (line 5) will be attempted, otherwise routing to the secondary (line 9) will occur.
4
An embedded OR assertion. Note that this will stop processing upon the first successful child (either line 5 or 6).
5
First child of the OR assertion in line 4. Routing is attempted to "backend1". If this is successful, processing of the entire policy fragment stops because the composite assertions in lines 4, 2, and 1 are satisfied.
6
Second child of the OR assertion in line 4. This is attempted only if routing in line 5 fails. Line 6 is another embedded AND assertion that is always designed to fail, because the assertion in line 8 will always fail.
 You may wonder, 
Why do I need another composite assertion? Why can't I simply add line 7 right after line 5?
 At first glance, this might be the easier solution: if the routing in line 5 fails, then simply log an audit saying so. However this causes another non-obvious logic error: replacing the composite assertion in line 6 with the assertion in line 7 will cause line 4 to always return 'true' (because the Add Audit Detail Assertion always returns 'true'). As a result, this causes the composites in lines 2 and 1 to also return true, meaning the alternate routing in line 9 will never be attempted even when the primary in line 5 fails.
7
First child of the AND assertion in line 6: This adds a message to the audit log by using the Add Audit Detail Assertion. This assertion always succeeds.
8
Second child of the AND assertion in line 6: The Stop Processing Assertion halts processing in that branch. This assertion always fails (that is returns 'false'). This is necessary to cause lines 6, 4, and 2 to return 'false', so that the alternate routing in line 9 is attempted.
9
Second child or the OR assertion in line 1; "backend2" is attempted only when the primary one fails.
Complex Policy Structures
The examples shown above are basic examples meant to provide a foundation to policy authoring. You can design policies with very complex interactions just by using the composite assertions, policy fragments. The key to success is to decompose problems into modular units and be careful with your policy logic.
To illustrate the power of policy, several CA applications (CA API Management OAuth Toolkit and the Mobile SSO capabilities within the CA Mobile API Gateway) are delivered entirely as policy. Both of these products use policy fragments extensively to boost reliability and lower maintenance.
All Assertion Failures are Not Equal
The information that is logged on the Gateway differs slightly depending on how an assertion "fails":
  • A typical failure, such as a Apply Rate Limit Assertion.
    If this failure is handled inside of a At Least One Assertion Must Evaluate to True Assertion folder, then the overall policy succeeds. If the assertion failure is 
    not
     handled, then the overall policy fails. If the policy fails, then all assertions (for that message) are logged.
  • An exception occurs, such as the Route via HTTP(S) Assertion routing to a nonexistent back end.
    If this failure is handled inside of a "At Least One..." folder, the policy could still succeed. However, regardless of the overall policy evaluation result, all assertions (for that message) are logged. Using the nonexistent back-end example, the following message is still logged even if you handle the routing exception:
    2017-02-14T16:40:45.697-0600 WARNING 17878 com.l7tech.server.policy.assertion.ServerHttpRoutingAssertion: 4042: Problem routing to http://blah/gw-events/routing. Error msg: Unable to obtain HTTP response from http://blah/gw-events/routing: Connection to http://elk:9200 refused. Caused by: Connection refused