Workflow Manager – v1.11.0-RC4
Introduction
Operation guide
Integration guide API reference

# Prerequisites

# Hardware

Here is the minimal recommended server configuration.
Please contact us for more precise recommendations depending on your signature throughput.

  • 1 core CPU
  • 2 GB RAM
  • 20 GB space available

# Software

  • Java 11 or higher (latest is recommended).
  • Latest version of Elasticsearch 7.x.
  • ClamAV. Note that the ClamAV daemon must be accessible over a TCP socket.

# Security considerations

The following security measures MUST be taken:

  • The application must be accessible over HTTPS through a reverse proxy. The application must not be exposed directly on the Internet.

  • The server must be protected against unauthorized access. Particularly, access to its administration interfaces and its storage devices must be restricted to authorized admins only. In addition, the jar file of the application must never, under any circumstances, be modified.

# Deployment

# Run the application

This application is a fully executable Spring Boot application.
In most operating system, it can be run with the following command, assuming Java is installed properly:

java -jar webapp.jar

In a Unix/Linux based operating system, you can simply run:

./webapp.jar

Use java -Xmx1024m -jar webapp.jar to change the maximum JVM memory usage.

# Configuration properties

Configuration properties can be passed to the application as command line arguments starting with --.
For example, the listening port of the server can be specified as follows:

java -jar webapp.jar --server.port=8080

Or directly:

./webapp.jar --server.port=8080

Jump to the application configuration for the list of available configuration properties.

# Systemd service

Most of modern Linux distributions make use of systemd to create background services and have them automatically started at server boot and restarted on unexpected termination.

To create a systemd service, first we create the sunnystamp user by running the following commands:

groupadd -r sunnystamp
useradd -r -g sunnystamp -d /home/sunnystamp -s /bin/bash sunnystamp
mkdir -p /home/sunnystamp
chown sunnystamp:sunnystamp /home/sunnystamp

Then we create a systemd unit file with name webapp.service and we place it in /etc/systemd/system:

[Unit]
Description=Lex Persona web application
After=syslog.target

[Service]
User=sunnystamp
Environment="LC_ALL=C"
ExecStart=/usr/bin/java -XX:MaxRAMPercentage=40.0 -XX:+ExitOnOutOfMemoryError -jar /path/to/webapp.jar --server.port=8080
SuccessExitStatus=143
Restart=on-failure

[Install]
WantedBy=multi-user.target

You can specify different path and parameters for the ExecStart field.

Now we can start the service with the following commands:

# Load the service 
systemctl daemon-reload
# Start the service now
systemctl start webapp.service
# Start the service automatically at boot
systemctl enable webapp.service

# Windows service

On Windows operating system, you can wrap the application as a Windows service by following these steps:

  1. Download winsw. Make sure to choose the correct version depending on your version of .NET.
  2. Rename the winsw executable to webapp.exe.
  3. Create an XML file named webapp.xml with the following content:
    <?xml version="1.0" encoding="UTF-8"?>
    <service>
        <id>webapp</id>
        <name>webapp</name>
        <description>Lex Persona web application</description>
        <executable>java</executable>
        <arguments>-jar "webapp.jar"</arguments>
        <logmode>rotate</logmode>
    </service>
    
  4. Create a folder with webapp.exe, webapp.jar and webapp.xml inside.
  5. Install the windows service by running the following command inside the folder.
    webapp.exe install
    
    The service should now appear in Windows Service Manager.

# Docker container

To create a docker image for the application, run the following command in the folder where the Dockerfile and the webapp.jar reside:

docker build -t sunnystamp/webapp .

To run the application in foreground and expose the listening port on the host:

docker run -p 8080:8080 -it sunnystamp/webapp --server.port=8080

Note that you will need to create volumes for the different folders in the application configuration.
For example, here is how you would mount your client folder in the container:

docker run -p 8080:8080 -v /path/to/clients:/clients -it sunnystamp/webapp \
    --server.port=8080 \
    --clientFolderPath=/clients

# Clustering

For resiliency purpose, you can replicate the application in a cluster environment simply by deploying the executable on different machines, placing them behind a load balancer. For such deployments, the following requirements must be met:

  • The clocks on the different machines must be synced periodically. This can be achieved using an NTP server.

  • Some folders used in the application configuration must be shared across the nodes. This can be achieved using an NFS or a CIFS server.

    Note: File attribute caching must be disabled for reads/writes to work properly. In case of an NFS server, the mount option noac must be specified. For a CIFS server, the mount option actimeo=0 must be specified.

As a suggestion, the client folder can be shared across the nodes, with read-only access. This will allow you to manage the client configuration in a centralized way.

# Port requirements

The Workflow Manager needs TCP port 8885 to be accessible by the reverse proxy. This port number can be changed via the server.port property in the application configuration.

The Workflow Manager also needs access to:

  • The Elasticsearch server, on the port exposed by Elasticsearch (the default port is TCP 9200).
  • The ClamAV daemon, on the port exposed by ClamAV (the default port is TCP 3310).

Furthermore, the application requires both HTTP (TCP, port 80) and HTTPS (TCP, port 443) access to the internet for the following features to work properly:

  • Access the timestamp server in order to produce timestamped signatures.
  • Download CRLs and access OCSP responders in order to check the revocation status of signer and CA certificates.

Also, in order to customize the consent pages for your clients, the application will make connections over HTTPS (TCP, port 443) to the Evidence Manager URL.

# Proxy configuration

If you want the application to connect to the outside world through a proxy, you can specify the host and port of the proxy as command line arguments, as well as the user name and password if your proxy requires an authentication:

java -jar webapp.jar \
    --proxyHost=my-proxy.local \
    --proxyPort=3128 \
    --proxyUser=my_proxy_user \
    --proxyPassword=my_proxy_password

Note that the application will create a TCP tunnel through the proxy for any outbound HTTP or HTTPS connections, so you must ensure that the HTTP CONNECT method is allowed. Typically on a Squid proxy, the following rule should be removed, or overridden:

# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports

# HTTPS configuration

You must deploy the application behind a reverse proxy so that it is not exposed directly on the internet. If you also need, you can enable HTTPS in the application itself using the application configuration:

java -jar webapp.jar --server.port=443 --server.ssl.enabled=true --server.ssl.key-store=keystore.p12 --server.ssl.key-store-password=change_me --server.ssl.keyStoreType=PKCS12 --server.ssl.key-alias=mykey

Use java -jar webapp.jar -Djavax.net.debug=ssl:handshake:verbose to debug issues with TLS handshakes.

# Web application firewall

If you want to use a web application firewall (WAF) in front of the application for security measures, you must ensure that your WAF does not block HTTP requests going to the application for the following methods:

  • GET
  • POST
  • PUT
  • DELETE
  • PATCH
  • OPTIONS

Also, since the application makes use of CORS, your WAF should not suppress or modify the following headers in the HTTP requests going to the application:

  • Origin
  • Access-Control-Request-Method
  • Access-Control-Request-Headers

And the following headers in the HTTP responses coming from the application:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Max-Age

# Backup

The Workflow Manager persistence is composed of:

  • Folders in the file system: store workflow documents and other tenant resources.
  • Elasticsearch cluster: indexes the workflows, users and tenants metadata.

# Folder backup

A folder backup is a backup of the following folders (see the application configuration for their default location):

  • exportFolderPath
  • resourceFolderPath

Note that it’s not required to perform atomic backups of your file system. You are free to make snapshots if your file system supports it, or to perform file-level backups of the folders (with the rsync command for instance).

# Elasticsearch snapshot

Please refer to the official Elasticsearch documentation to learn how to snapshot your Elasticsearch cluster.

# Disaster recovery

In a disaster recovery scenario, you should restore both a folder backup and an Elasticsearch snapshot.

Note that to prevent inconsistencies, you should always restore an Elasticsearch snapshot that was made before the folder backup you want to restore. Also note that you should not restore an Elasticsearch snapshot that was made too long before the folder backup. The garbageMaxAge property in the application configuration governs the delay after which files are purged from the folders once they are no longer used. By default, files are purged after 12 hours, which means:

  • You have to make sure the delay between your Elasticsearch snapshot and your folder backup is less than 12 hours. It’s recommended to create a folder backup right after each Elasticsearch snapshot.
  • You can always restore an Elasticsearch snapshot that was created in the last 12 hours without the need to restore a folder backup.
  • You don’t need to keep folder backups that are older than your oldest Elasticsearch snapshot.

# Configuration

# Application configuration

The application configuration can be changed via configuration properties.
You can specify configuration properties using command line arguments starting with -- as described earlier.

Key Default value Description
resourceFolderPath ${user.home}/sgs-wm-data/resources/ Folder where tenant resources are stored. In a cluster, this folder MUST be shared across the nodes.
requestFolderPath ${user.home}/sgs-wm-data/requests/ Folder where request files are stored. In a cluster, this folder MUST be shared across the nodes.
exportFolderPath ${user.home}/sgs-wm-data/exports/ Folder where exports are stored. In a cluster, this folder MUST be shared across the nodes.
tempFolderPath ${user.home}/sgs-wm-data/temp/ Temporary folder. This folder MUST NOT be shared across the nodes of a cluster.
signedDataFolderPath signed_data/ Folder used to store signed data into ZIP archive
logMaxAge 2592000000 Maximum age for log entries (30 days by default).
garbageMaxAge 43200000 Delay after which files scheduled for deletion are actually deleted from disk (12 hours by default).
webhookEventMaxAge 2592000000 Maximum age for webhook events (30 days by default).
accessTokenHashIterations 10000 Number of iterations when hashing access tokens.
wmUrl URL of the Workflow Manager, for development. Leave empty to allow tenant resolution based on domain name using the X-Forwarded-Host header. Only localhost URLs are allowed.
uiUrl URL to the static UI files, for development. Only localhost URLs are allowed.
adminsPasswdPath ${user.home}/sgs-wm-data/admins.passwd Path to the admins.passwd file.
confScanRate 30000 Configuration change detection frequency (every 30 seconds by default).
logging.file.name ${user.home}/sgs-wm-data/logs/wm.log Path to the log file.
server.port 8885 Listening port of the server.
smtpServerName localhost Email server hostname
smtpServerPort 25 Email server port
smtpServerUsername Username for email server authentication
smtpServerPassword Password for email server authentication
smtpServerStartTls false Whether or not the email server supports StartTLS
smtpSenderEmail no-reply@sunnystamp.com The email address to use as sender for all emails
clamavServerName localhost Clamav server hostname
clamavServerPort 3310 Clamav server port
proxyHost The host name of the proxy server, if any.
proxyPort 80 The port number of the proxy server.
proxyUser The user name for proxy authentication.
proxyPassword The user password for proxy authentication.
server.ssl.enabled false Whether or not to enable HTTPS.
server.ssl.keyStoreType JKS Type of keystore to be used to configure HTTPS. Possible values: JKS, PKCS12.
server.ssl.key-store Path to the keystore to be used to configure HTTPS
server.ssl.key-store-password Password of the keystore to be used to configure HTTPS
server.ssl.key-alias Alias of the key to be used to configure HTTPS
server.ssl.key-password Password of the key to be used to configure HTTPS
spring.codec.max-in-memory-size 500000 Maximum size of buffers in RAM
elasticsearchUrls http://localhost:9200 Comma separated list of endpoint URLs to connect to Elasticsearch
helios.namespace XADES_122 Helios configuration Namespace
helios.policy.digestAlgorithm SHA256 The digest algorithm of the XAdES detached signature policy
helios.policy.id 1.2.250.1.131.1.5.18.21.1.7 The OID of the Helios signature policy
helios.policy.digestValue GbP1WjbTrHp6h9zlsz5RN7AqkJbnDNDOAQzgm1qzIJ4= The base64 encoded digest of the Helios signature policy
helios.policy.uri https://www.collectivites-locales.gouv.fr/files/finances_locales/dematerialisation/ps_helios_dgfip.pdf The URL of the Helios signature policy
helios.canonicalizationMethod.keyInfo EXCLUSIVE Canonicalizations
xadesDetached.namespace XADES_132 XAdES detached configuration Namespace
xadesDetached.policy.digestAlgorithm SHA256 The digest algorithm of the XAdES detached signature policy
xadesDetached.policy.id 1.2.250.1.115.200.300.4 The OID of the XAdES detached signature policy
xadesDetached.policy.digestValue lLKFDAaR8NxNtrf1cIlmULQgp1GS+7igKN8p7pqy3G0= The base64 encoded digest of the XAdES detached signature policy
xadesDetached.policy.uri https://sites.banque-france.fr/igc/signature/ps/ps_1_2_250_1_115_200_300_4.pdf The URL of the XAdES detached signature policy
xadesDetached.canonicalizationMethod.keyInfo EXCLUSIVE Canonicalizations
cades.policy.digestAlgorithm SHA256 CAdES configuration The digest algorithm of the CAdES signature policy
cades.policy.id 1.2.250.1.115.200.300.4 The OID of the CAdES signature policy
cades.policy.digestValue lLKFDAaR8NxNtrf1cIlmULQgp1GS+7igKN8p7pqy3G0= The base64 encoded digest of the CAdES signature policy
cades.policy.uri https://sites.banque-france.fr/igc/signature/ps/ps_1_2_250_1_115_200_300_4.pdf The URL of the CAdES signature policy
cadesDetached.policy.digestAlgorithm SHA256 CAdES detached configuration The digest algorithm of the CAdES detached signature policy
cadesDetached.policy.id 1.2.250.1.115.200.300.4 The OID of the CAdES detached signature policy
cadesDetached.policy.digestValue lLKFDAaR8NxNtrf1cIlmULQgp1GS+7igKN8p7pqy3G0= The base64 encoded digest of the CAdES detached signature policy
cadesDetached.policy.uri https://sites.banque-france.fr/igc/signature/ps/ps_1_2_250_1_115_200_300_4.pdf The URL of the CAdES detached signature policy
pdftronCustomKey Custom PDFTron licence Key, for development
tsaUrlQualified https://tsa.sunnystamp.com/tsa RFC 3161 compliant timestamp server.
tsaUserName User name timestamp server.
tsaPassword Password timestamp server.
email.validation.pattern This property sets the regular expression (regex) used for validating email addresses If not specified, the application uses a default regex for email validation “^[_A-Za-z0-9-\+\’]+(\.[_A-Za-z0-9-\+\’]+)@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)(\.[A-Za-z]{2,})$”

${user.home} is the home folder of the user running the application, typically /home/sunnystamp if you have created a systemd service.

Please note that application configuration changes can NOT be applied without restarting the application.

# Admin interfaces

The admin interfaces (API and GUI) can be enabled simply by declaring at least one admin user in the admins.passwd configuration file. The path of the admins.passwd file is defined in the application configuration.

The admins.passwd file allows us to declare admin users with their respective password hashes in a Unix fashion way. For example, here is how you would declare two admin users (john and jack) in the admins.passwd file:

john:$6$rounds=100000$GAOcXXTBkR0OcaQk$bnCMTTOWc5jw5fQ7VziaHQEpUVM/KHWKs5RUcA8blRtehYKanOS311GeGdo6TEa9okLw2xF4jw.3doxUPPY6o0
jack:$6$rounds=100000$4DUwSzeHJRevBuKW$3vfincGEEAMCRVfQwRACWgUwTQjokUQcMiCsmxtXlvsQAVApka.GJ8xkfARXQzsjxITUQ16j6YzrdUvMyJcNz/

Use one of the following Unix commands to produce your password hash:

# Using mkpasswd:
mkpasswd -m sha-512
# Or using openssl:
openssl passwd -6 -salt rounds=100000\$`head -c12 /dev/urandom | openssl base64`

Once admin users are declared, the admin GUI can be accessed from a web browser using the following URL:

https://{hostname}:{port}/admin

Note that it’s highly recommended to:

  • disable the admin interfaces on instances that are accessible to regular users,
  • enable the admin interfaces on instances that are restricted to admin users, in a limited access network.

Please check the clustering requirements for multiple instances deployment.