a) Tyr Webservice
The Tyr webservice or tyrservice is a XML-RPC based service, providing webSignatureOffice functionality for integration in third party applications (http://en.wikipedia.org/wiki/XML-RPC).
The Tyr webservice can be used by a variety of XML-RPC libraries which are available for all major programming languages (https://www.tutorialspoint.com/xml-rpc/xml_rpc_examples).
Preview + Testing
The Tyr webservice can be tested with a test account on webSignatureOffice.com, a development server can be provided on request.
Authentication and request signing
In order to use this service two keys have to be requested from StepOver:
- an application key (customer key)
- a request signing key (shared secret)
All service calls (other than login) must contain a sessionId string as follows:
session_id:timestamp:unique_id:customer_key
- session_id: the string returned after successful login
- timestamp: unix timestamp
- unique_id: a nonce, best is to use a UUID generator
- customer_key: the application key supplied by StepOver
Example: 7bd273e259b20052666ce9194468c439:1563264207:b9554fc6-43a2-467d-b4e9-7c694306f639:af5539de0753868ef1872410b2eb7366
TyrService help and error codes
The tyrservice always returns HTTP status code 200 (OK). If an error occurs, custom error codes are returned in the XML response body. The response is a struct or map, which also contains a fault string or error message.
The complete list of tyrservice methods and error codes can be found in the tyrservice help documentation: https://www.websignatureoffice.com/tyrservice
XML-RPC spec: http://xmlrpc.scripting.com/spec.html
HTML server implementation: http://ws.apache.org/xmlrpc
To activate gzip compression the http header Content-Encoding has to be set to gzip, this reduces the required bandwidth.
Implementing the TyrService in third party applications
Each request is signed as follows:
The request signature hash is built by concatenating the request xml and the shared_secret, then SHA256 hashing the result.
The request signature hash (hex representation) is sent as a HTTP header "X-SOSIGNATURE".
*Please note*: The shared_secret should be securely stored, in an app it should be obfuscated.
Example Client in Java (Apache XMLRpc)
public class TyrServiceClient { XmlRpcClient client = new XmlRpcClient(); XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); String sharedSecret; String customerKey; public TyrServiceClient(String host, String sharedSecret, String customerKey) throws MalformedURLException, NoSuchAlgorithmException, KeyManagementException { this.customerKey = customerKey; this.sharedSecret = sharedSecret; config.setServerURL(new URL(host + "/tyrservice")); client.setConfig(config); client.setTransportFactory(new LoggingTransportFactory(client)); config.setEnabledForExtensions(true); TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { // Trust always } public void checkServerTrusted(X509Certificate[] certs, String authType) { // Trust always } }}; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); // Create empty HostnameVerifier HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String arg0, SSLSession arg1) { return true; } }; sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(hv); } class LoggingTransportFactory extends XmlRpcSun15HttpTransportFactory { XmlRpcClient client; @Override public XmlRpcTransport getTransport() { return new LoggingTransport(client); } public LoggingTransportFactory(XmlRpcClient pClient) { super(pClient); client = pClient; } } class LoggingTransport extends XmlRpcSun15HttpTransport { @Override protected InputStream getInputStream() throws XmlRpcException { BufferedReader reader = null; StringBuilder respBuf = new StringBuilder(); try { InputStream inputStream = super.getInputStream(); reader = new BufferedReader(new InputStreamReader(inputStream)); String line = null; while ((line = reader.readLine()) != null) { respBuf.append(line); } } catch (IOException e) { e.printStackTrace(); } return new ByteArrayInputStream(respBuf.toString().getBytes()); } @Override protected void writeRequest(ReqWriter reqWriter) throws XmlRpcException { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); reqWriter.write(os); String requestHeader = ""; requestHeader = new String(Hex.encodeHex(DigestUtils.sha256(os.toString() + sharedSecret))); this.setRequestHeader("X-SOSIGNATURE", requestHeader); super.writeRequest(reqWriter); } catch (Exception e) { e.printStackTrace(); } } public LoggingTransport(XmlRpcClient pFactory) { super(pFactory); } } public Object execute(String method, Object[] param) throws XmlRpcException { Object execute = client.execute("tyrservice." + method, param); return execute; }
Example client with imports:
Request example to upload and view a signature request
1.) TyrService.login: create a sessionId
Method: tyrservice.login | Return: sessionId
XmlRpcClient client = new XmlRpcClient(); Object[] loginParams = new Object[]{ "mylogin", "mypassword" }; //parameters are username/login and password sessionId = (String) client.execute( "login", loginParams ); String sessionIdString = sessionId + ":" + System.currentTimeMillis() / 1000 + ":" + UUID.randomUUID() + ":" + customerKey; //the sessionIdString has to be added for each method call, e.g. for method processXml( string sessionIdString, base64 xml )
2.) TyrService.processXml: Upload a document with signature definition
For this step, you need to encode your PDF-file into base64. The base64 code will be placed then inside the tag <PDF> at the end of the XML-File.
The structure of the XML will be shown later at topic "Input-XML Extensions" or here: XML Sample
Please continue with the implementation steps.
Method: tyrservice.processXML | Return: envelope or document id
Object[] params = new Object[]{ sessionIdString, xmlBytes }; //parameters are sessionIdString and XML bytes Integer documentId = (Integer) client.execute( "processXml", params );
-> The file is uploaded on the webSignatureOffice server as a PDF now.
3.) TyrService.getEncryptedParameters: Create a viewer link for other users
The method getEncryptedParameters encrypts the information for a viewer url. The returned encrypted string is added as the querey parameter "xen" to a process-servlet (path /process) call. The process servlet decrypts the parameter and redirects to the viewer. The method requires admin rights because links for other users can be created.
TimeLimitedViewer URL format: https://websignatureoffice.com/process?xen=JLKASDJLKASDJasdasd&locale=de
Encrypted parameters contain
- a timestamp: Until the viewer link is valid
- a user_id: Id of the user the link is created for
- a id: document or envelope id
In the method, it must be defined, which viewer type is requested as the first parameter:
- "tlev": TimeLimitedEnvelopeViewer
- "tldv": TimeLimitedDocumentViewer
String userId = 123; //can be obtained with the method tyrservice.getUserMetaByLogin; see below String time = Long.toString( System.currentTimeMillis() + ( 1000 * 60 * 2880 ) ); //the validity of the URL, for example 48 hours String documentId = 2222; //the response from the processXML call Map<String, String> values = new HashMap<>(); values.put( "u", userId ); values.put( "t", time ); values.put( "d", documentId ); Object[] params = new Object[]{ sessionIdString, "tldv", values }; //action is TimeLimitedDocumentViewer String encryptedParams= (String) client.execute( "tyrservice.getEncryptedParameters", params ); String url = host + "/process?xen=encryptedParams;
Method: tyrservice.getUserMetaByLogin | Return: user metadata (necessary for document links)
3.1 TyrService.getTimeLimitedViewerUrl: create a viewer link for own user
To create a TimeLimitedViewer link for the own user, the method getTimeLimitedViewerUrl can be used. The method directly returns the URL. The method has five parameters:
- sessionId
- viewerType:
- tlev: TimeLimitedEnvelopeViewer
- tldv: TimeLimitedDocumentViewer
- timestamp
- locale
The method can be called by a registered user and doesn't require admin rights. Therefore only links for documents or envelopes the user is associated with as a signer, owner or observer can be created. The userId is not necessary to call the methotd.
String timestamp = Long.toString( System.currentTimeMillis() + ( 1000 * 60 * 2880 ) ); //the validity of the URL, for example 48 hours String documentId = 2222; //the response from the processXML call Object[] params = new Object[]{ sessionIdString, "tldv", documentId, timestamp, "en" }; //viewerType is TimeLimitedDocumentViewer String url = (String) client.execute( "tyrservice.getEncryptedParameters", params );
Input-XML Extensions
For customers which used or still use our eSignatureOffice in the past: webSignatureOffice uses the same standard input-XML as eSignatureOffice does, but with a few extensions.
You can find the definition of the input XML here: Input-XML
In the signature field definition a user name can be set. The UserName is either a valid email adress or the user name of a registered user. If no user name is defined, the logged in user is taken as signer
<Signatures> <Signature> <Placeholder>Signature 1</Placeholder> <Width>4</Width> <Height>3</Height> <UserName>myLogin</UserName> ...
<Signatures> <Signature> <Placeholder>Signature 1</Placeholder> <Width>4</Width> <Height>3</Height> <UserName>username</UserName> <SignatureType>2</SignatureType> ...
You can also rename the uploaded PDF with the PDFName tag.
With this tag you can change the standard upload name into something more suitable.
<Signatures> <Signature> <Placeholder>Signature 1</Placeholder> <Width>4</Width> <Height>3</Height> <UserName>username</UserName> <SignatureType>2</SignatureType> ... </Signature> </Signatures> <PDFName>AlternativePDFName</PDFName>