Task validation on REST-API complete / Task variables update

Hi,

I have a security question regarding using camunda through REST-API.

I would like to have variables validation when using any endpoint that can change task/process instance variables.

For example, when I use the endpoint to complete a task, I would like to validate the variables sent by the complete request.
I also need to make sure that on the complete task request, only some fields are taken into account.
Imagine I have a “Select assignee” task:

1 - I want to make sure that on the complete request for this specific task, only the assignee variable will be changed/added to the process instance.
2 - I want to make sure that the assignee is in the following collection: [‘person1’, ‘person2’].

How is this possible to achieve?

Thanks in advance.

Best Regards,
Pedro Silva

@psilva you can use listeners on the tasks to preform the validation before the task is execute (Execution Listener: Start). How are you using the engine? Java delegates, scripting, embedded, shared?

Also this might be of interest: Form Server Validations: Generic Form Validator using Javascript which will let you execute a script based on the submission prior to execution of the task or process instance.

Hello @StephenOTT, I am using Angular only with ajax requests to the engine-rest that is provided by camunda.
I thought of Listeners to validate the data and that might work for what I need, thanks!

Still, it doesn’t solve the problem I also reffered.
In the complete request body, I can send the variables I want to change in the process, even if in that step it shouldn’t be possible to change it.
For example, if I have a variable “risk” in the process, anyone with access to the task can make a request that changes that value, even though it is a calculated value. Is there anyway to prevent this behaviour?

I thought that it would be possible to describe which variables would be changeable in a specific task.

EDIT: By complete request, I mean the rest api endpoint request that allows the completion of a task (post-complete).

Best Regards,
Pedro Silva

Yes thats a problem i have encountered. See the link above with the Generic Form validator code. In that code you could write a small script that checks the submission for which data is allowed to be submitted. I am just about to release a update to the code that will enable multiple script files to be used. So should be easy for you to write a small validator script per Submission Form, and use shared scripts across all setups

Camunda does not have Variable level permissions.

Thank you, will check that and test it.
Meanwhile I will leave this open in case camunda team has a solution for this problem.

@psilva
your 3 solutions are generally:

  1. Add execution listeners that throw a error (thus causing a rollback) when some data changed, but it it will likely be problematic to capture the changes
  2. Add a form validator such as the links above (except the links above are for a “generic” solution that lets you run your validator through scripts
  3. Add some sort of global submission listener that tracks the attempted changes.

The script scenario i mentioned looks like this:

@psilva
See this release: Release v0.3.0 - Dynamic JS file selection · StephenOTT/camunda-form-validator-js-server · GitHub

Further notes in:

So with the first option it will be hard to see which variables changed, is that right?
With the second option I tried form fields, but that doesn’t prevent variables that are not there to be changed.
The third option seems promising, but I lack the experience in camunda to try that yet.

Maybe the first option is the right one for my specific case.

I am trying to understand how camunda developers handle this security issue.

In my experience, it seems like it will be problematic to detect the changes (for #1)

Can you explain your issue with the second option? You should be able to define all logic. What is your specific logic story/scenario. Will provide you with a example. You dont need to use the generic script. You can just add your own validator as per: https://docs.camunda.org/manual/7.8/user-guide/task-forms/#form-field-validation. The Generic JS version is so you can upload your validations along side your HTML angular forms as part of a single package during the deployment.

The third option i see as having the same issue as the first option.

Yes, with form fields I can specify the validation for all fields, for example, if I call POST /task/{id}/complete with the following data:
{
…“variables”: {
… …“decision”: {“type”: “String”, “value”: “accept”},
… …“risk”: {“type”: “String”, “value”: “low”}
…}
}

I can validate that decision is a value required and can make other validations. But I cannot prevent risk to be changed (and that’s a calculated value).
If an user has experience in rest, he can easily make this request and change variables that he wasn’t supposed to.
What I want in this case is to prevent any variables beside decision to be added or changed in the customer decision task.

Process example:

@psilva so:

But I cannot prevent risk to be changed (and that’s a calculated value).

Yes you can prevent that change:

When the submission occurs, in the script you define that “risk” cannot be part of the submission. If the field is found you throw an error; or you just completely ignore the risk variable.

With the Form validator usage you are actually using: Submit Task Form | docs.camunda.org and not using the /complete. The task is only “completed” is the form validator returns “true” because the submission data was “Valid” / aka: the risk field was not attempted to be modified.

I see, I will check that, will reply here with the results. Thanks!

As a exmaple of using validate.js you could setup whitelist https://validatejs.org/#utilities-clean-attributes or you could use the contains check: https://validatejs.org/#utilities-contains and if your submission contains the “risk” variable you throw an error / fail the validation.

Did you make progress?

@psilva here is a working example of “Banned Fields”

load('classpath:validationResult.js')
load('classpath:validate.min.js')
var JSONObject = Java.type('org.camunda.bpm.engine.impl.util.json.JSONObject')

var jsonSubmission = JSON.parse(new JSONObject(submissionValues).toString())

// Validate.js Constraints
function getConstraints() {
  var constraints = {
    age: {
      presence: true,
      numericality: {
        onlyInteger: true,
        greaterThan: 18,
        lessThanOrEqualTo: 125,
      }
    }
  };
  return constraints
}

// List of fields that are not allowed to be changed
function bannedFields(){
  // could also be loaded from another location (like a yaml or json file)
  return [
    "risk",
    "owner",
    "master_field",
    "current_state",
    "flagged",
    "priority"
  ]
}

// Check if the submission has any of the banned fields
function checkForBannedFields(submission, bannedFields) {
  // Loop through list of banned fields (nashorn loop)
  for each (var field in bannedFields){
    var hasBannedField = validate.contains(submission, field)
    // if a banned field was found then return true:
    if (hasBannedField == true) {
      return true
    }
  }
  // If no banned fields were found:
  return false
}

// if there is a banned field:
if (checkForBannedFields(jsonSubmission, bannedFields())){
  validationResult(false, {
                          "detail": "VALIDATE.JS", 
                          "message": 'Submission contains a banned field: ' + JSON.stringify(bannedFields())
                        }
                  )

// If no banned fields were found:
} else {
  // If no banned fields then continue:
  // Run Validations against Validate.js
  var validation = validate(jsonSubmission, getConstraints())

  if (validation === undefined) {
    validationResult(true)
  } else {
    validationResult(false, {
                              "detail": "VALIDATE.JS", 
                              "message": JSON.stringify(validation)
                            }
                      )
  }
}

you can see full working example in: camunda-form-validator-js-server/bpmn/banned-fields-example at master · StephenOTT/camunda-form-validator-js-server · GitHub

when the user task is submitted you will get a response such as:

{
    "type": "RestException",
    "message": "Cannot submit task form df4fe4ec-4336-11e8-b611-0242ac130002: Invalid value submitted for form field 'banned-fields': validation of validator(io.digitalstate.camunda.JsFormValidation) failed."
}

and the console will output:

Caused by: org.camunda.bpm.engine.impl.form.validator.FormFieldValidationException: Submission contains a banned field: ["risk","owner","master_field","current_state","flagged","priority"]

Thank you @StephenOTT but I didn’t have time to try that yet. Will come back to you as soon as i have it working.
Thanks