Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » scout » @InputValidation and validation rules(Central input validation point in the server)
@InputValidation and validation rules [message #1430629] Wed, 24 September 2014 15:32 Go to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1243
Registered: October 2011
Senior Member
Since Scout 3.8.0 (Juno) we have the possibility to have a central input validation point in the server (See Bug 349659). I was asked how the mechanism works and I wanted to share it here.

The idea of central input validation is following: when a method is called in the server, the parameters are checked (including a partial or full check of the content of the formData).

From a security point of view, it can be useful to check the input parameters. Think of:
* Malicious clients
* Unsafe communication channel used by the client to communicate with the server (man-in-the-middle attacks).
I am not a security expert and you should check by yourself is the mechanism I describe make sense for your scout application or not.

----------------------------
== Information in the formData ==

If you have a look at the formData classes, the properties (relevant for validation) defined with the getConfiguredXxxx() methods are added to the FormData class.

Example (field):
@Order(10.0)
public class MyStringField extends AbstractStringField {

  @Override
  protected boolean getConfiguredMandatory() {
    return true;
  }

  @Override
  protected int getConfiguredMaxLength() {
    return 100;
  }

  //...
}


Example (field data):
public static class MyString extends AbstractValueFieldData<String> {

  private static final long serialVersionUID = 1L;

  public MyString() {
  }

  /**
   * list of derived validation rules.
   */
  @Override
  protected void initValidationRules(Map<String, Object> ruleMap) {
    super.initValidationRules(ruleMap);
    ruleMap.put(ValidationRule.MANDATORY, true);
    ruleMap.put(ValidationRule.MAX_LENGTH, 100);
  }
}


----------------------------
Using this information in the server
If you want to use this information server side, you need to change the Transaction delegate used in your application:

1/ You need your own TransactionDelegate class:

The easiest way is to extend DefaultTransactionDelegate. By default the method validateInput(IValidationStrategy, Object, Method, Object[]) is empty. To activate the default input validation, just override the method and call defaultValidateInput(IValidationStrategy, Object, Method, Object[]).
import java.lang.reflect.Method;

import org.eclipse.scout.rt.server.DefaultTransactionDelegate;
import org.eclipse.scout.rt.shared.validate.IValidationStrategy;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;

public class MyAppTransactionDelegate extends DefaultTransactionDelegate {

  public MyAppTransactionDelegate(Bundle[] loaderBundles, Version requestMinVersion, boolean debug) {
    super(loaderBundles, requestMinVersion, debug);
  }

  @Override
  protected void validateInput(IValidationStrategy validationStrategy, Object service, Method op, Object[] args) throws Exception {
    defaultValidateInput(validationStrategy, service, op, args);
  }
}


2/ After that you need your own service tunnel (MyAppServiceTunnelServlet)

This ServiceTunnelServlet will work with the TransactionDelegate class created in step 1:

import org.eclipse.scout.rt.server.ServiceTunnelServlet;
import org.eclipse.scout.rt.shared.servicetunnel.ServiceTunnelRequest;
import org.eclipse.scout.rt.shared.servicetunnel.ServiceTunnelResponse;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;

public class MyAppServiceTunnelServlet extends ServiceTunnelServlet {

  private static final long serialVersionUID = 1L;

  @Override
  protected ServiceTunnelResponse runServerJobTransactionWithDelegate(ServiceTunnelRequest req, Bundle[] loaderBundles, Version requestMinVersion, boolean debug) throws Exception {
    return new MyAppTransactionDelegate(loaderBundles, requestMinVersion, debug).invoke(req);
  }
}


3/ Register your service tunnel servlet in the server XML. Search for the servlet declaration with the alias "/process" and replace the class attribute with your new class created in step 2:

<servlet
      alias="/process"
      class="myapp.server.servlets.MyAppServiceTunnelServlet">
  <init-param
        name="min-version"
        value="0.0.0">
  </init-param>
</servlet>


----------------------------
== What is checked? ==

Then on each of your services, you can define which validation strategy should be applied (on the service class or on each of the methods)
There are 3 validations strategies:
* IValidationStrategy.PROCESS: all rules defined in each formFieldData of the formData are checked.

* IValidationStrategy.QUERY: check reduced to some rules (MaxLength, CodeValue, LookupValue, RegexMatch)

* IValidationStrategy.NO_CHECK: no check at all.

If you have some mandatory fields in you form, in when you open the form, you some of this field might be empty. It is probably not a good idea to use IValidationStrategy.PROCESS on the load() or on the prepareCreate() methods.

Here is how a process service might looks like:
import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.rt.shared.validate.IValidationStrategy;
import org.eclipse.scout.rt.shared.validate.InputValidation;
import org.eclipse.scout.service.AbstractService;

public class MyService extends AbstractService implements IMyService {

  @InputValidation(IValidationStrategy.QUERY.class)
  @Override
  public MyFormData prepareCreate(MyFormData formData) throws ProcessingException {
    //TODO business logic here.
    return formData;
  }

  @InputValidation(IValidationStrategy.PROCESS.class)
  @Override
  public MyFormData create(MyFormData formData) throws ProcessingException {
    //TODO business logic here.
    return formData;
  }

  @InputValidation(IValidationStrategy.QUERY.class)
  @Override
  public MyFormData load(MyFormData formData) throws ProcessingException {
    //TODO business logic here.
    return formData;
  }

  @InputValidation(IValidationStrategy.PROCESS.class)
  @Override
  public MyFormData store(MyFormData formData) throws ProcessingException {
    //TODO business logic here.
    return formData;
  }
}

----------------------------

Related posts:
* Legacy Hint WarnMissingInputValidation
* Validation rules explained by Ivan Motsch.

Re: @InputValidation and validation rules [message #1434623 is a reply to message #1430629] Tue, 30 September 2014 10:57 Go to previous message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1243
Registered: October 2011
Senior Member
Read also in the wiki: Communication > Input/Output Validation
Previous Topic:Form Generator based on DB Table layout
Next Topic:Case-sensitivity in SQL binding
Goto Forum:
  


Current Time: Tue Oct 24 02:29:49 GMT 2017

Powered by FUDForum. Page generated in 0.02402 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software