-
Notifications
You must be signed in to change notification settings - Fork 10
Rule engine API
With grules you are able to apply preprocessing rules not only to request parameters but to any arbitrary map that contains variable names and their values. You can apply a rules script to such an input via the Grules.applyRules
or Grules.applyGroupRules
method. These methods take a script class, a parameters map, and an optional environment functions and variables as its parameters. Here is an example of unit tests for a rules script that validate two parameters, id
and name
(for the sake of readability we use the Groovy test framework Spock):
def "Test method for rules script with one default group"() {
when:
def grules = new Grules() // for static calls use GrulesAPI class
def r = grules.applyRules(MyFormGrules, [id:1, name:"Bob"])
then:
r.cleanParameters == [id:1, name:"Bob"]
}
def "Test method for rules script with two groups"() {
when:
def r = grules.applyGroupRules(MyGrules, [GET: [id:1, name:"Bob"], POST: [password: "pass"]])
then:
r.cleanParameters == [GET: [id: 1, name: "Bob"], POST: [:]]
}
Similarly, you can call Grules from Java:
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", new Integer(1));
grules.applyRules(MyGrules.class, parameters);
You can also pass additional custom functions as a third method argument:
def functions = [isJohn: {it == "John"}]
def result = grules.applyRules(FunsGrules, [name: "Bob"], functions)
FunsGrules file:
name isJohn
Converters and validators can be tested as regular Groovy code, e.g.:
expect:
CommonFunctions.trim(" test") == "test"
The other example where you might need to explicitly call the rule engine is for preprocessing of non-query string parameters. In addition to GET/POST request parameters and cookies, a part of the input data can be passed to an application via a URL path. For instance, the popular site StackOverflow.com uses a schema where a question id and canonical title are placed after a module name in a URL path. Here is a typical address of a question page:
http://stackoverflow.com/questions/111102/javascript-closures-work
Similarly to tampering with HTTP parameters, an attacker can perform a request manipulation and modify a URL to conduct a path traversal or injection attack. For example, in the URL above one can easily falsify the question id, and if the value is then inserted into the web page without any validation, site visitors may be exposed to an XSS attack. To keep application data secure a site need to be protected from such evasion.
In grules preprocessing of values from a URL path can be performed by applying script rules to a URL_PATH group which includes path parameters that require validation. For our Stackoverflow.com example the code in a page controller might look like this:
def questionId = getQuestionId(url)
def questionTitle = getQuestionTitle(url)
def parameters = [URL_PATH: [id: questionId, title: questionTitle]]
def r = grules.applyGroupRules(QuestionGrules, parameters)
Then in the QuestionGrules:
id toPositiveInt
title match(/[\w\-]/)
As a future work, we are also going to parallelize processing of each parameter to leverage multi-core CPUs.