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).

A help documentation of the webSignatureOffice services / methods can be displayed by a HTTP GET request on our tyrservice URL https://websignatureoffice.stepover.de:8450/tyrservice (stage server, can be down at times).

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 (tyrservice ID)
  • a request signing key (shared secret)

All service calls (other than login) must contain a sessionId string as follows:

session_id:timestamp:unique_id:application_key

  1. session_id: the string returned after successful login
  2. timestamp: unix timestamp
  3. unique_id: a nonce, best is to use a UUID generator
  4. application_key: the application key supplied by StepOver

Example: 7bd273e259b20052666ce9194468c439:1563264207:b9554fc6-43a2-467d-b4e9-7c694306f639:af5539de0753868ef1872410b2eb7366

How to implement the Tyr webservice 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 request signature key should be securely stored, in an app it should be obfuscated.

Example Client in Java (Apache XMLRpc)

TyrClient
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:

TyrServiceClient.java

Requests

1.) First you have to create a session ID for the sessionIdString.

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.) Now you have the option for uploading XML-Files which contains the PDF.

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: documentID 

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.) To view the uploaded PDF, you need to create a document link. For this you have to encode the document relevant data for a URL-safe link.

The method getUrlSignature generates a signature string which is part of the document URL.

Method: tyrservice.getUrlSignature | Return: URL signature for a action handled by the process servlet

/*Collecting the document link relevant data*/
 
String userId = 123; //you will get your userId 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 signature = (String) client.execute( "tyrservice.getUrlSignature", params );

String url = host + "/process?x=tldv&u=" + userId + "&t=" + time + "&d=" + documentId + "&xx=" + signature;
 


Method: tyrservice.getUserMetaByLogin | Return: user metadata (necessary for document links)

Object[] params = new Object[]{ sessionIdString, "mylogin" }; // parameters are sessionIdString and username/login
HashMap<String,Object> userMetadata = (HashMap<String, Object>) client.execute( "tyrservice.getUserMetaByLogin", params );
 
String userId = userMetadata.get("user_id").toString();


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: /wiki/spaces/PESO/pages/79200348


The following extended tags can be used to optimize the use of the /wiki/spaces/PESO/pages/79200348 with webSignatureOffice:

In the signature field definition a user name can be set, 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>
        ...


Additionally a signature type can be defined:
0 = stamp data (text/image) without signature
1 = digital stamp (signature with user certificate instead of hand-written signature)
2 = html-signer signature only
3 = pad signature only
4 = app signature only (QR code)
If no signature type is defined, a selection window appears. The signer can choose between following types: StepOver signature pad OR one of our apps OR HTML-signer (with a pen or your finger on your mobile device)


<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.

PDFName
	<Signatures>
    	<Signature>
    		<Placeholder>Signature 1</Placeholder>
			<Width>4</Width>	
        	<Height>3</Height>	
        	<UserName>username</UserName>
			<SignatureType>2</SignatureType>
			...
		</Signature>
	</Signatures>
<PDFName>AlternativePDFName</PDFName>



Tyr webservice help documentation

This service implements a simple XML-RPC interface to  the FRIGG Server (web frontend), that can be used by a variety of clients.

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.

*********************

Error codes: 

*********************
100 = service signature not valid, session expired
101 = braga server exception, severe
102 = login data incorrect
103 = max login tries reached, account locked, try again in 5 minutes
104 = document locked, try again later
105 = document upload failed
106 = permission denied
107 = user unknown
108 = no signature request
109 = duplicate pdf field name
110 = unexpected error
111 = document not found
112 = DB error
113 = invalid adhoc code
114 = operation time out
115 = audit trail server exception *********************

TyrService Methods:

a list of all tyrservice methods is available under:

https://websignatureoffice.stepover.de:8450/tyrservice (Stage server, can be down at times)

request examples:

tyrservice.login

<?xml version="1.0" encoding="UTF-8"?>
<methodCall xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
  <methodName>tyrservice.login</methodName>
  <params>
    <param>
      <value>foo</value>
    </param>
    <param>
      <value>bar</value>
    </param>
  </params>
</methodCall>


tyrservice.getUrlSignature

<?xml version="1.0" encoding="UTF-8"?>
<methodCall xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
<methodName>tyrservice.getUrlSignature</methodName>
    <params>
<param>
<value>eb9cd247e5850e785093aee86b9b35b9:1581602515:4942e688-d29f-49ed-aafc-8a6d49ec1eb5:abc439de0723860ee8871234b2eb73a8</value>
</param>
<param>
<value>tldv</value>
</param>
<param>
<value>
<struct>
<member>
<name>t</name>
<value>1581775315944</value>
</member>
<member>
<name>d</name>
<value>22186</value>
</member>
<member>
<name>u</name>
<value>2451</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>

response examples:

tyrservice.login

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
  <params>
    <param>
      <value>eb9cd247e5850e785093aee86b9b35b9</value>
    </param>
  </params>
</methodResponse>


tyrservice.getUrlSignature

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
<params>
<param>
<value>DJ5S_aMp2NQPy6Dgwxg8bGeKPRfDEPKJajJOcQ</value>
</param>
</params>
</methodResponse>