Thinkfree Office - Sharepoint WOPI Host Integration Guide

Modified on Sat, Aug 22 at 5:14 PM

1. Overview

This document describes how to connect SharePoint (on-premise) as the host with TFO as the editor.

The systems used in this description are as follows:


2. Configuration

2.1 Add Adapter

In Admin page > Adapter Management > Add Adapter, register the attached JAR with the following values.

Item

Value

Notes

Adapter name

wopi

Use this fixed value

Class name

com.tf.se.adapter.impl.wopi.WopiAdapter

 

Description

Adapter description

Optional

JAR file

adapter-wopi-*.jar

 

 

File download link: adapter-wopi-0.0.3-SNAPSHOT.jar


2.2 Add WOPI Settings

In Admin page > Settings > Additional setting, add the wopiDomain key/value.

Admin settings page




Adding the wopiDomain row


Notes on entering the wopiDomain property value

Enter the origin (scheme + host + port) at which TFO is exposed externally.

wopiDomain = https://wopi.thinkfree.com


If this value is left empty, /hosting/discovery returns 503 Service Unavailable with the following message, and the process stops:


'wopiDomain' is not configured. Set 'wopiDomain' key in admin settings before requesting discovery.


2.3 Deploy Hosting.war

2.3.1 Upload hosting.war

Copy the hosting.war file to ~/wo-server  (In the integrated Docker container, copy to the thinkfree-office-was-1 container)

ubuntu@Ubuntu:~$ docker cp hosting.war thinkfree-office-was-1:/home/thinkfree/wo-server
Successfully copied 28.8MB to thinkfree-office-was-1:/home/thinkfree/wo-server/hosting.war

file download link: hosting.war


Before copyAfter copy


2.3.2 Configure httpd via vhosts.conf

Navigate to the location of the vhosts.conf file in the thinkfree-office-m16-was-1 container.

ubuntu@Ubuntu:~$ docker exec -it thinkfree-office-was-1 /bin/bash
[thinkfree@thinkfree-was ~]$ cd /etc/httpd/conf.d
[thinkfree@thinkfree-was conf.d]$ ls
README  autoindex.conf  userdir.conf  vhosts.conf  welcome.conf
[thinkfree@thinkfree-was conf.d]$ vi vhosts.conf



Edit /etc/httpd/conf.d/vhosts.conf as follows.

<VirtualHost*:80>
        Timeout 600
        KeepAlive On
        KeepAliveTimeout 75

        <Directory />
                <Limit PATCH DELETE OPTIONS>
                        Order deny,allow
                        Deny from all
                </Limit>
        </Directory>

        ServerName 127.0.0.1
        ServerAlias */cloud-office
        ServerAlias */hosting
        ServerAlias */webword
        ServerAlias */webCell
        ServerAlias */webShow

        ProxyPass /cloud-office ajp://127.0.0.1:8081/cloud-office
        ProxyPassReverse /cloud-office ajp://127.0.0.1:8081/cloud-office

        ProxyPass /hosting ajp://127.0.0.1:8081/hosting
        ProxyPassReverse /hosting ajp://127.0.0.1:8081/hosting

        ProxyPass /webword/connectToChannel ws://127.0.0.1:8080/webword/connectToChannel
        ProxyPassReverse /webword/connectToChannel ws://127.0.0.1:8080/webword/connectToChannel
        ProxyPass /webword ajp://127.0.0.1:8081/webword
        ProxyPassReverse /webword ajp://127.0.0.1:8081/webword

        ProxyPass /webCell/connectToChannel ws://127.0.0.1:8080/webCell/connectToChannel
        ProxyPassReverse /webCell/connectToChannel ws://127.0.0.1:8080/webCell/connectToChannel
        ProxyPass /webCell ajp://127.0.0.1:8081/webCell
        ProxyPassReverse /webCell ajp://127.0.0.1:8081/webCell

        ProxyPass /webShow/connectToChannel ws://127.0.0.1:8080/webShow/connectToChannel
        ProxyPassReverse /webShow/connectToChannel ws://127.0.0.1:8080/webShow/connectToChannel
        ProxyPass /webShow ajp://127.0.0.1:8081/webShow
        ProxyPassReverse /webShow ajp://127.0.0.1:8081/webShow
</VirtualHost>



2.3.3 Restart the service

Restart the service using the commands below.

ubuntu@Ubuntu:~$ docker restart thinkfree-office-was-1


2.3.4 Single-origin configuration (** IMPORTANT ** Required)

/hosting and /cloud-office must be served from the same origin.

https://wopi.thinkfree.com/hosting/* <- wopi WAR
https://wopi.thinkfree.com/cloud-office/* <- TFO


If the port or domain is split across origins, the launch POST sent by the host gets routed to a static file instead, causing a 405 Method Not Allowed error.


2.3.5 Verify deployment

Enter the following command in the VM terminal outside the container.

curl -i https://wopi.thinkfree.com/hosting/discovery
  • 200 OK + XML → normal
  • 503 → wopiDomain not configured (see 2.2)

Example result (for reference in a local VM environment without a domain configured)

3. Integration

3.1 WOPI Host (SharePoint)

The WOPI host only needs to know a single discovery URL for the client (TFO). The host downloads XML from that URL and registers the extension → Action URL (urlsrc) mapping and the proof-key into its farm; in SharePoint, the result of this registration is called a WOPI Binding.


TFO discovery URL:

https://{wopiDomain}/hosting/discovery


The steps below are performed in the SharePoint Management Shell.


3.1.1 Prerequisite check

The SharePoint server must be able to reach the TFO discovery URL directly for binding registration to succeed.



Test-NetConnection "wopi.thinkfree.com" -Port 443

ComputerName : wopi.thinkfree.com
RemoteAddress : 13.209.94.28
RemotePort : 443
 TcpTestSucceeded : True

Invoke-WebRequest -Uri "https://wopi.thinkfree.com/hosting/discovery" -UseBasicParsing

StatusCode : 200
Content-Type: application/xml


This is normal if the result above is returned. If it fails, check the firewall/security groups and section 2.3.4 first.


If SharePoint runs over HTTP while TFO runs over HTTPS, HTTP OAuth must be allowed so documents can be opened and saved using OAuth tokens.

(Get-SPSecurityTokenServiceConfig).AllowOAuthOverHttp


If the result is False, run the following:

$c = Get-SPSecurityTokenServiceConfig
$c.AllowOAuthOverHttp = $true
$c.Update()

3.1.2 Register WOPI Binding (run discovery)

First, check the existing binding. If the result is empty, a new registration can be made; if another WOPI client is already registered, clean it up with Remove-SPWOPIBinding before proceeding.


Get-SPWOPIBinding


The command below causes SharePoint to read TFO's discovery XML. For -ServerName, entering only the host name makes SharePoint automatically look up /hosting/discovery.

New-SPWOPIBinding -ServerName "wopi.thinkfree.com"


The registration result lists the Action registered for each extension defined in the discovery XML.

Application : writer
Extension : ODT
Action : edit
IsDefaultAction : True
ServerName : wopi.thinkfree.com
WopiZone : external-http
...

Next, specify which net-zone from the discovery XML SharePoint should use. This must exactly match the net-zone value in the discovery XML; the TFO default template is external-http.

Set-SPWOPIZone -Zone "external-http"
Get-SPWOPIZone


Check the registration result.

Get-SPWOPIBinding |
Where-Object { $_.Extension -in @("DOCX", "XLSX", "PPTX") } |
Select-Object Application, Extension, Action, IsDefaultAction, WopiZone, ServerName

Application : writer
Extension : DOCX
Action : edit
IsDefaultAction : True
WopiZone : external-http
ServerName : WOPI.THINKFREE.COM

Application : calc
Extension : XLSX
Action : edit
...

Once the binding is registered successfully, also verify the following three items in the discovery XML:

  • Does the net-zone name match the value specified in Set-SPWOPIZone?
  • Do all urlsrc values point to a /hosting/ path and end with "?"?
  • Are the proof-key's value, modulus, exponent, and old* attributes all populated?


SharePoint reads and caches the discovery XML only once, at the moment the binding is registered. If wopiDomain, the discovery template, or the proof-key changes on the TFO side, you must re-read it with the command below for the change to take effect.


Update-SPWOPIBinding -ServerName "wopi.thinkfree.com"


3.1.3 Verify document opening

Once the binding is registered, the "Open" menu in the SharePoint document library shows an "Open in Word/Excel/PowerPoint Online" item. This works from configuration alone, with no additional development, but the button label cannot be changed (changing it requires additional development).

Normal behavior when opening a docx/xlsx/pptx document is as follows:

  • SharePoint calls the TFO launch page with POST {urlsrc}?WOPISrc=...
  • The launch page redirects to /cloud-office/api/wopi/{fileName}/open?...
  • The TFO editor opens, and saving updates the original document in SharePoint

TFO editor open with the test document


Check the WOPI authentication and Proof verification logs on the SharePoint side with the command below.

Get-SPLogEvent -StartTime (Get-Date).AddMinutes(-5) |
    Where-Object {
        $_.Message -match "SPApplicationAuthenticationModuleV2|Invalid Proof|Malformed WOPI|CheckFile|IsAuthenticated"
    } |
    Sort-Object Timestamp |
    Format-List Timestamp, Category, Level, Correlation, Message

If everything is normal, you will see IsAuthenticated=True and WOPI new request (CheckFile) in the log.


3.2 WOPI Client (Thinkfree Office)

Once you complete the process in 3.1, the Proof Key-related properties are automatically generated and stored in the DB. You can check them in Admin page > Settings > User properties.


Key

Description

wopiPublicKey / wopiPrivateKey

RSA 2048 key pair (Base64)

wopiValue

discovery's value — in CAPI PUBLICKEYBLOB format

wopiModulus / wopiExponent

discovery's modulus / exponent

wopiOldValue / wopiOldModulus / wopiOldExponent / wopiOldPrivateKey

The previous generation's keys. On first creation, these hold the same values as the current keys

wopiExpirationDate

Expiration date/time. Creation time + 6 months

wopiDiscovery

The template automatically saved on the first discovery request


Key rotation behavior

When discovery is called after wopiExpirationDate has passed, a new key is generated and the existing key is moved to wopiOld*.


When the key is rotated, SharePoint must re-read discovery (Update-SPWOPIBinding). Until that re-read happens, verification proceeds through the oldvalue path.


Generated Wopi properties


4. Troubleshooting

4.1 /hosting/discovery returns 503

Cause — the wopiDomain key is not configured.

Fix — configure wopiDomain per section 2.2. Enter only the origin, with no path.


4.2 405 Method Not Allowed when opening a document

Cause — urlsrc points to a static file path such as /cloud-office/word.html. The host calls the launch page with POST, but static files don't accept POST.


Fix — change urlsrc to the form %%WOPI_DOMAIN_*%%/hosting/word.html?. /hosting is handled by a controller that accepts POST and redirects to GET.


4.3 WOPISrc parameter is passed malformed

Cause — if urlsrc does not end with "?", the host appends "&WOPISrc=" directly onto it, corrupting the path. (WEBCOM-5699)


Fix — verify that every urlsrc value ends with "?". The default template is automatically corrected when discovery is generated.

SharePoint is lenient and sometimes still works despite this, but other WOPI hosts will fail. Be sure to check this if you have manually edited the template.


4.4 500 error when opening a document — invalid cookie name

Symptom:

IllegalArgumentException: cookie name [...] is a reserved token


Cause — TFO uses docId as the cookie name for statistics. If the fileid provided by the host contains characters outside the RFC 6265 token spec (especially "="), Tomcat throws this exception.


Fix — the current implementation skips setting the cookie when the name is invalid for use as a cookie. If the issue still occurs, check the host's fileid format.

  • Safe: hex format (e.g., b47d1ce6...)
  • Problematic: base64 format (e.g., local!ODE2...Mw==)


4.5 400 Bad Request — access_token is required

Cause — the host's launch POST does not include access_token.


Fix — check SharePoint's WOPI binding and zone settings. If this was reproduced by opening the launch URL directly in a browser, that is expected behavior.


4.6 Proof Signature Invalid (500)

Symptom — the following message appears in the SharePoint ULS log:

WOPI InitAndValidateForFile ExpectedFailure: invalid proof signature for file.
 Unable to verify WOPI Signature - Malformed WOPI proof key data: ...
CryptographicException: Bad Version of provider.

Cause — the proof-key from discovery does not match the private key TFO uses to sign, or wopiValue is not in the standard CAPI PUBLICKEYBLOB format.


Fix:

  • Have SharePoint re-read discovery (Update-SPWOPIBinding).
  • If it still fails, delete the Proof Key properties (e.g., wopiPublicKey) and call discovery again to regenerate the keys.
  • A non-standard wopiValue saved by an older version is automatically corrected to the standard CAPI PUBLICKEYBLOB format when discovery is called, and re-saved to the DB. Immediately after this correction, SharePoint's discovery needs to be refreshed.

4.7 Save fails / LOCK error

Cause — mismatched X-WOPI-Lock key in LOCK/UNLOCK requests.


Check — check docId and connId in the [WOPI] [lock] / [WOPI] [unlock] log entries in adapterInfoLogger.


4.8 Document fails to open at all (conversion error)

Confirm — check the filter server URL configuration first. This affects document opening in general, independent of WOPI.


4.9 Adapter not found

Cause — the registered adapter name is not "wopi".


Solution — Match the adapter name to [adapter name] according to 2.1.3 , or modify the wopidiscovery path to match the actual adapter name.urlsrc



Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article