Trusted Central Signing Service - API - Document (PDF) signing

Prerequisites

- PAS 4.1 or higher installed

- The reader of this document should have some basic knowledge about PhenixID Server.

- Changes will be made to the file phenix-store.json, so please make sure to have a backup  of this file.

Add custom CA

Follow this guide to add custom CA to PhenixID Signing Services. This step is recommended to follow to make sure the certificate created before the signing operation is issued by a CA which is trusted in your organisation.

How to add custom CA to PhenixID Server

Add module for file upload via API

- Login to PhenixID Authentication Services - Configuration manager

- Click on the tab Advanced

- Click on the pen to the right of Modules

- Append the files module

{
		"name": "com.phenixidentity~phenix-files",
		"enabled": "true",
		"id": "files_01",
		"config": {
			"read_only": "false",
			"name": "integration_dev",
			"auth_method": "pipe",
			"auth_pipe": "files_auth_01",
			"store_impl": "com.phenixidentity.files.internal.SessionFilesStore"
		}
	}

NOTE: The values for auth_method can be pipe, basic_auth

- Change the name value to suit your environment. The name value will be part of the url that will receive file uploads. (Example: https://demo.phenixid.net/files/integration_dev)

- If you would like to bind the files-api module to another http port (other than default), add a http_configuration_ref parameter to the config section with a value pointing to the id of the http connection.

- Click Stage Changes and Commit Changes

 

- Click on the pen to the right of NODE_GROUPS

- Add the module "files_01" to module_refs.

- Click Stage Changes and Commit Changes

Add pipe for files-api client authentication

- Logon to Configuration Manager

- Click Advanced

- Click Pipes

- Add this pipe for authentication of api client.

{
		"id": "files_auth_01",
		"valves": [
{   
 "name": "HttpBasicAuthValve",
 "enabled": "true",
 "config": {
  "username_dest": "uid",
  "password_dest": "pwd"
 }
},
			{
 "name": "InternalUserStoreValidatorValve",
 "enabled": "true",
 "config": {
  "username": "{{attributes.uid}}",
  "password_param_name": "{{attributes.pwd}}"
 }
},
{
 "name": "ItemCreateValve",
 "enabled": "true",
 "config": {
  "dest_id": "{{attributes.uid}}"
 }
}
]
	}

- Click Stage changes and commit changes

Add api username and password

- Logon to Configuration Manager

- Click Advanced

- Click Internal users

- Copy an object

- Paste object

- Set id (username) and password in object

	{
		"id": "sign_api_client",
		"password": "secret",
		"description": "Sign api client caller"
	} 

- Change the id and password to suite your needs.

- Click Stage changes and Commit changes. The password will be encrypted once the config is saved.

Add prism modules

- Login to configuration manager

- Click Advanced

- Click Modules

Add these modules:

{
		"id": "pdf_sign_prism_01",
		"name": "com.phenixidentity~phenix-prism-fedsigning",
		"enabled": "false",
		"prism_enabled": "true",
		"config": {
			"display_name": "PhenixID Signing Service",
			"base_uri": "sign",
			"sign_auth_redirect_url": "/pdf_sign/authenticate/pdf_sign_auth_01",
			"sign_pipe": "pdf_sign_sign_pipe_01"
		}
	},
{
		"id": "pdf_sign_prism_00",
		"name": "com.phenixidentity~phenix-prism",
		"enabled": "true",
		"config": {
			"base_url": "/pdf_sign",
			"auth_redirect_url": "/pdf_sign/authenticate/pdf_sign_auth_00",
			"module_refs": "pdf_sign_prism_01"
		}
	}

- If you would like to bind the prism modules to another http port (other than default), add a http_configuration_ref parameter to the config section with a value pointing to the id of the http connection.

- Change uri values to suite your needs (ie /pdf_sign)

- Click Stage Changes and Commit Changes

 

- Click on the pen to the right of NODE_GROUPS

- Add the module "pdf_sign_prism_00" to module_refs.

- Click Stage Changes and Commit Changes

Add primary authenticator

Add primary authenticator. This authenticator will parse incoming jwt token and add values to the session.

- Login to configuration manager

- Click Advanced

- Click Authentication - HTTP

Add this authenticator:

{
		"id": "pdf_sign_auth_00",
		"alias": "pdf_sign_auth_00",
		"name": "PipeAuthenticator",
		"configuration": {
			"pipeID": "pipe_pdf_sign_auth_00",
			"successURL": "/pdf_sign"
		}
	}

- Click Stage changes and Commit changes

Add pipe

- Click Advanced

- Click Pipes

Add this pipe:

{
		"name": "Pdf sign initial auth",
		"description": "Pipe for initial auth in pdf_sign. Parse jwt token and add properties to session",
		"enabled": "true",
		"id": "pipe_pdf_sign_auth_00",
		"valves": [
			{
				"name": "ItemCreateValve",
				"enabled": "true",
				"config": {
					"dest_id": "_"
				}
			},
			{
				"name": "JWTTokenParserValve",
				"enabled": "true",
				"config": {
"exec_if_expr" : "request.get('Authorization')!=null",
					"token_parameter": "Authorization",
               "certfilepath" : "",
					"additional_attributes": [
						"id",
						"failURL",
						"successURL",
                  "cancelURL"
					]
				}
			},
{
"name": "JWTTokenParserValve",
"enabled": "true",
"config": {
"exec_if_expr" : "request.get('access_token')!=null",
"token_parameter": "access_token",
               "certfilepath" : "",
"additional_attributes": [
"id",
"failURL",
"successURL",
                  "cancelURL"
]
}
},
			{
				"name": "SessionLoadValve",
				"enabled": "true",
				"config": {
					"id": "{{item.jwt_id}}",
					"require_session": "true",
					"require_auth_session": "false"
				}
			},
			{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "file_id",
					"value": "{{item.jwt_id}}"
				}
			},
			{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "content",
					"value": "{{session.content}}"
				}
			},
			{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "success_url",
					"value": "{{item.jwt_successURL}}"
				}
			},
			{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "failure_url",
					"value": "{{item.jwt_failURL}}"
				}
			},
                        {
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "cancel_url",
					"value": "{{item.jwt_cancelURL}}"
				}
			},
			
			{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "content_type",
					"value": "application/pdf"
				}
			}		]
	}

Add signature method(s)

First of all, decide which authenticator(s) is to be used from this list of available authenticators for PhenixID web apps authentication.

- Click on the pen to the right of Authentication - HTTP

- Add your authenticator(s) via the step-by-steps described here.
Make sure the successURL is /pdf_sign/sign/api/sign.

 

{
		"alias": "pdf_sign_auth_01",
		"name": "PostUidAndPassword",
		"displayName": "Username and password",
		"configuration": {
         "pipeID": "pipe_pdf_sign_auth_01",
			"successURL": "/pdf_sign/sign/api/sign"
		},
		"id": "pdf_sign_auth_01"
	}

In this example, a simple username and password authenticator is used.

- Click Stage changes and Commit changes

- Click on the pen to the right of Pipes

- Add this pipe configuration. 

{
		"id": "pipe_pdf_sign_auth_01",
		"valves": [
			{
				"name": "LDAPSearchValve",
				"config": {
					"connection_ref": "replace_LDAP_scenario_id",
					"base_dn": "replace_base_dn",
					"scope": "SUB",
					"size_limit": "0",
					"filter_template": "(&(objectclass=*)(sAMAccountName={{request.username}}))",
					"attributes": ""
				}
			},
			{
				"name": "LDAPBindValve",
				"config": {
					"connection_ref": "replace_LDAP_scenario_id",
					"password_param_name": "password"
				}
			},
{
				"name": "SessionLoadValve",
				"enabled": "true",
				"config": {
					"id": "{{request.session_id}}"
				}
			},
{
				"name": "SessionPropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "auth_user",
					"value": "{{request.username}}"
				}
			},
{
				"name": "SessionPersistValve",
				"enabled": "true",
				"config": {}
			}
		]
	}

- Change the "replace_LDAP_scenario_id (reference to LDAP connection) to a value that suits your configuration (Example: "a932a759-893a-4eee-9c93-0a3b80af0918"). 

- Change "replace_base_dn". (Example: "DC=phenixid,DC=local").

- Replace filter and attributes to suit your configuration.


- Click Stage changes and Commit changes

Add execution flow (pipe) to sign pdf

- Click on the pen to the right of Pipes

- Add this pipe. The configuration in this pipe will fetch the logged-in user attributes from the LDAP store and use these attributes to populate the certificate that will be created in run-time. The certificate will then be used to perform the signing operation of the incoming PDF file.

Please note that this might not suit your environment. Valves can be replaced, removed or added based on your needs. Please view the documentation to get a list of available valves.

 

Change these values to suit your environment:

- LDAPSearchValve:

- Change the "replace_LDAP_scenario_id" . (Example: "a932a759-893a-4eee-9c93-0a3b80af0918").

- Change "replace_base_dn". (Example: "DC=phenixid,DC=local").

- Replace filter and attributes to suit your configuration.

- CreateShortTermKeyStoreValve: subjectKeyParamater, caTemplateKeyParameter (for testing purposes the builtin CA delivered with PhenixID Server can be used. The ID can be found in the file phenix-store.json in the section "CA_CONFIGURATIONS".)

- AddImageToPDFValve, use this valve if you want to add a picture to the end of the PDF file. Point to the picture that should be used. The position is set with the parameter "imagelocation" and value can be northwest, northeast and so on.

 

{
		"name": "Pdf sign - Execute Sign",
		"description": "Signs file stored in supplied session (file_id) and replaces the file with the signed copy.",
		"enabled": "true",
		"id": "pdf_sign_sign_pipe_01",
		"valves": [
			{
				"name": "SessionLoadValve",
				"enabled": "true",
				"config": {
					"id": "{{request.session_id}}"
				}
			},
			{
				"name": "LDAPSearchValve",
				"config": {
					"connection_ref": "replace_LDAP_scenario_id",
					"base_dn": "replace_base_dn",
					"scope": "SUB",
					"size_limit": "0",
					"filter_template": "sAMAccountName={{session.auth_user}}",
					"attributes": "givenName,sn,mail"
				}
			},
{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "signerID",
					"value": "{{session.auth_user}}"
				}
			},
			{
				"name": "SessionLoadValve",
				"enabled": "true",
				"config": {
					"id": "{{request.file_id}}",
					"require_session": "true",
					"require_auth_session": "false"
				}
			},
			{
				"name": "PropertyAddValve",
				"enabled": "true",
				"config": {
					"name": "content",
					"value": "{{session.content}}"
				}
			},
			{
				"name": "PropertyBase64DecoderValve",
				"config": {
					"source": "content",
					"dest": "temporary"
				}
			},
			{
				"name": "CreateShortTermKeyStoreValve",
				"enabled": "true",
				"config": {
					"subjectKeyParamater": "CN={{item.givenName}} {{item.sn}} ({{item.mail}}),replace_base_dn",
					"caTemplateKeyParamater": "customsignca",
					"keyUsage": [
						"true",
						"true"
					]
				}
			},
			{
				"name": "PADESSignValve",
				"enabled": "true",
				"config": {
					"keyStoreID": "{{item.keyStoreId}}",
					"pdfSourceData": "{{item.temporary}}",
					"pdfTarget": "document"
				}
			},
			{
				"name": "SessionPropertyReplaceValve",
				"enabled": "true",
				"config": {
					"name": "content",
					"value": "{{item.document}}"
				}
			},
			{
				"name": "SessionPropertyReplaceValve",
				"enabled": "true",
				"config": {
					"name": "modified",
					"value": "{{now}}"
				}
			},
			{
				"name": "SessionPersistValve",
				"enabled": "true",
				"config": {}
			},
{
				"name": "EventValve",
				"config": {
					"event_key": "EVT_000052",
					"parameters": [
						{
							"parameter": "duser",
							"value": "{{item.signerID}}"
						},
						{
							"parameter": "msg",
							"value": "Successfully signed"
						},
						{
							"parameter": "phenixIDIdentifier",
							"value": "SIGN"
						},
						{
							"parameter": "proto",
							"value": "PADES"
						}
					]
				}
			}
		]
	}

 

- Click Stage changes and Commit changes


Add execution flows (pipe) for verification of signed PDF

- Click on the pen to the right of Modules

- Enable http on the pipes module by adding http_enabled=true.

- If you would like to bind the pipes modules to another http port (other than default), add a http_configuration_ref parameter to the config section with a value pointing to the id of the http connection.

{
		"name": "com.phenixidentity~phenix-pipes",
		"singleton": "true",
		"config": {
			"http_enabled": "true"
		},
		"enabled": "true",
		"created": "2017-07-03T11:38:03.057Z",
		"id": "01ffd70e-b5fb-4c06-b040-b61760424bf6"
	}

 

- Create a jks trust store file

- Add all the CAs you trust to issue certificates to sign PDFs

- Place the jks file in a folder (example: C:/Program Files/PhenixID/SigningService/custom/trustedcas.jks)

- Click on the pen to the right of Pipes

- Add this pipe. The configuration in this pipe will validate the signature to make sure the data has not been altered.

Please note that this might not suit your environment. Valves can be replaced, removed or added based on your needs. Please view the documentation to get a list of available valves. Please also view this document to see how the certificates can be extracted from the signatures (in order to validate the certificates using this valve).

{
		"id": "SignAppVerifyPipeAPI",
		"description": "Verify signed document via API ",
		"http_enabled": "true",
		"http_path_pattern": "PUT:/pipes/verifysign",
		"valves": [
			{
				"name": "ItemCreateValve",
				"config": {
					"dest_id": "verification_result"
				}
			},
			{
				"name": "PropertyAddValve",
				"config": {
					"name": "b64",
					"value": "{{request.body}}"
				}
			},
			{
				"name": "PropertyBase64DecoderValve",
				"config": {
					"source": "b64",
					"dest": "temporary"
				}
			},
			{
				"name": "PropertyRemoveValve",
				"enabled": "true",
				"config": {
					"name": "b64"
				}
			},
			{
				"name": "PDFSignatureStatusValve",
				"enabled": "true",
				"config": {
					"pdfSource": "{{item.temporary}}",
              "trustStorePath": "C:/Program Files/PhenixID/SigningService/custom/trustedcas.jks",
			     "trustStorePassword": "secret (change this to your jks file pwd)"
				}
			},
			{
				"name": "PropertyRemoveValve",
				"enabled": "true",
				"config": {
					"name": "temporary"
				}
			}
		]
	}

- Click Stage changes and Commit changes


Add successful signatures report

Test

Follow the document found in the chapter Developer integration guide to test your setup.

 

Troubleshooting

Check server.log file.