Steps to create a new custom workflow

by David Hetzl

The new workflow will be called "example_wf_request" throughout this document. For creating customized workflows this text has to be substituted with whatever name is chosen for the actual workflow.

Files that need to be created:

Files that need to be changed:


1) File 'workflow_def_example_wf_request.xml'

This file specifies the different states which are valid for the corresponding workflow. For each state zero to many activities (= actions) can be stated, which will define the valid state transitions. These are explained in detail in the next section.

States can be declared as autorun, meaning that the stated action should be run automatically once the workflow switches to this state. If more than one workflow activity is specified a condition must be used to decide which of the actions must be executed.

Example:

  <state name="APPROVED" autorun="yes">
    <description>I18N_OPENXPKI_WF_STATE_EXTERNAL_CERTIFICATE_TRUST_REQUEST_APPROVAL</description>
    <action name="create_database_entry"
	    resulting_state="ENTRY_CREATED">
          <condition name="secure_email_set"/>
    </action>

    <action name="finish_transaction"
	    resulting_state="SUCCESS">
          <condition name="!secure_email_set"/>
    </action>
  </state>

This example specifies the state "APPROVED". Once the workflow reaches this state it automatically executes the action "create_database_entry" or "finish_transaction", depending on the current value of the evaluated condition "secure_email_set". The resulting state also differs based on this evaluation ("ENTRY_CREATED" or "SUCCESS"). Note that '!' can be used to invert the result of a condition.

Activities (=actions) mentioned in this file are specified as following:

  <action name="finish_transaction"
	    resulting_state="SUCCESS">
          <condition name="!secure_email_set"/>
  </action>

For a detailed explanation about 'Activities' please refer to the section File 'workflow_activity_example_wf_request.xml'.

Conditions are specifed as follows:

  <condition name="secure_email_set"/>

Please refer to section File 'workflow_condition.xml' for a detailed explanation on conditions.


2) File 'workflow_activity_example_wf_request.xml'

This file goes into more detail regarding activities (which are called "actions" in the Workflow.pm definitions). Activities are Perl modules which should return 1 after succesfull completion. Any kind of operations can be performed here, but typically this involves workflow manipulations or even database transactions. E.g. adding a certificate file which was uploaded through the OpenXPKI web interface to the certificate database. The module must have an execute() method, which will be executed during runtime. All activities inherit from the "Activity" module ('use base qw( OpenXPKI::Server::Workflow::Activity );'). Parameters for activities can be passed in the 'action' tag of the XMl definition file.

Every action of this custom workflow must be specified in this file and all fields (variables that are saved in the workflow) have to be stated which are changed or created during this activity's execution. Failure to do so will result in an exception when trying to access a field name which has not been specified. Also all validators which have to be evaluated during this activity are named here. The actual Perl module/class that is called when executing the action is part of the action tag, as can be seen in the next example:

  <action name="import_data"
      class="Workflow::Action::Null">

      <field name="cert_data"/>	<!-- X.509-Certificate in PEM -->
      <field name="company"/>	<!-- Name of the external company -->
      <field name="comment"/>	<!-- Comments from creator -->

      <!-- Checks if the RT ticket ID is existing-->
      <validator name="TicketExists">
      </validator>

      <!-- Checks if CRL is accessible, when specified -->
      <validator name="CRLaccessible">
      </validator>

  </action>

This action will invoke the module workflow::Action:Null, which just does nothing but can be used when there is no need to do anything "special". It is called from the HTML::Mason code which just saves the mentioned fields into the workflow if no validators fail. It has two validators which will both be evaluated and the action will only complete successfully if both return the value 1.

Another example for an action tag which includes a parameter follows:

  <action name="process_crr"
	  class="OpenXPKI::Server::Workflow::Activity::Tools::Export"
          use_destination="0">
  </action>

This action parameters can be queried from within the Perl module like this:

  my $self = shift;
  <...>
  my $dest = $self->param('use_destination');

A special kind of action uses the notification module. This can be called when there is the need to interact with the request tracking system. An example can be seen below:

  <action name="close_removal_ticket"
          class="OpenXPKI::Server::Workflow::Activity::Tools::Notification"
          message="ect_removal_close">
  </action>

It invokes the special "Notification" module which reads the notification.xml file to see which interactions are linked with the parameter that is passed in the message tag ("ect_removal_close") and executes them. Currently there is the option to open new tickets, close existing ones, create a new comment in a ticket and create a correspondence (which sends out an email to the requestor of the ticket). When this module is used all messages have to be specified accordingly in the notification.xml file.

The validators are specified in this file like the following example:

  <validator name="CRLaccessible"
  </validator>

Please refer to the next section for a detailed explanation of validators.


3) File 'workflow_validator_example_wf_request.xml'

This file describes the validators which have been named in the file of the last section. Validators must evaluate to true (=1) or else the corresponding activity will not be executed. They inherit from the base class 'Workflow::Validator' ('use base qw( Workflow::Validator );') and all processing is done in the validate() method. If the validation fails it should return a descriptive exception of what went wrong. Also paramater names can be specified, whose values can be derived from within the Perl module. This is useful for setting config items without the need to change the Perl source code and recompile it. The following example specifies the validator "ValidApprovalSignature":

Example:
  <validator name="ValidApprovalSignature"
             class="OpenXPKI::Server::Workflow::Validator::ApprovalSignature">
      <!-- if you set the following parameter to 1, you can enforce
           signatures on all CSR approvals -->
      <param name="signature_required" value="0"/>
  </validator>

The validator parameter "signature_required" can be accessed from within a Perl module in the _init() method with the following syntax example:

sub _init {
    my ( $self, $params ) = @_;
    if (exists $params->{'signature_required'}) {
        $self->signature_required($params->{'signature_required'});
    }
	return 1;
}

4) File 'workflow.xml'

This file lists all 'worflows', 'activities', 'validators' and 'conditions' below the corresponding sections. For our example we would need to add the following three lines:

    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="workflow_def_example_wf_request.xml"/>
    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="workflow_activity_example_wf_request.xml"/>
    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="workflow_validator_example_wf_request.xml"/>

Alternatively, if an all-in-one style deployment is used, you will need to include these files at the corresponding place in your config.xml. If you want to check in the changes, you will need to edit the template files in trunk/deployment/etc/templates/default, which specify both options.


5) File 'workflow_condition.xml'

This file specifies all conditions which can be used for the state transition evaluation mentioned in the 'workflow_def_example_wf_request' section. Conditions are Perl modules which inherit from the base class 'Workflow::Condition' ('use base qw( Workflow::Condition );'). After evaluation they either return 1 (=condition is true) or an exception (=condition is false). The condition check is done by calling its evaluate() method, so this is where the implementation should go.

The 'condition' tag includes a logical name and a binding to a Perl module, which is evaluated. The condition used in our former example is defined as follows:

  <condition name="secure_email_set" class="OpenXPKI::Server::Workflow::Condition::SecureEmailSet">
    <param name="RDN_filter" value="CN,O"/>
  </condition>

The condition parameter, used in this example, can be accessed from within the Perl module in the _init() method like follows:

  __PACKAGE__->mk_accessors( 'RDN_filter' );
  sub _init
  {
    my ( $self, $params ) = @_;
    if (exists $params->{RDN_filter}) {
        $self->RDN_filter($params->{RDN_filter});
    }
  }

Note: The mk_accessors method is used to also allow the parameter to be called from outside of the _init() method using '$self->RDN_filter()'.

ACL conditions for authorization are stated similiar, with the keyword 'ACL' in front of the name.

Example:
  <condition name="ACL::reject_crr" class="OpenXPKI::Server::Workflow::Condition::ACL">
    <param name="activity" value="reject_crr"/>
  </condition>

6) File 'notification.xml'

This file specifies all "messsages" and the corresponsing actions that should be executed when this message is passed as parameter. As already mentioned there are four possible transactions that can be performed. The following section lists all of them together with an examplary usage: