1
0
mirror of https://github.com/cs3org/wopiserver.git synced 2025-04-18 13:04:00 +03:00

Updated the whole repo to remove all vendor/storage-specific references.

This is in preparation to join the CS3 Organisation
This commit is contained in:
Giuseppe Lo Presti 2020-04-21 16:25:45 +02:00
parent 9077610692
commit 25788c0fe6
11 changed files with 47 additions and 52 deletions

View File

@ -1,22 +1,14 @@
# WOPI Server
A Web-application Open Platform Interface (WOPI) gateway for CERNBox
to embed Microsoft Office Online into the CERNBox/OwnCloud web interface
A Vendor-neutral Web-application Open Platform Interface (WOPI) gateway for EFSS,
to integrate several Office Online platforms including Microsoft Office Online and Collabora Online.
Author: Giuseppe.LoPresti@cern.ch <br/>
Contributions: Michael.DSilva@aarnet.edu.au
Initial revision: December 2016 <br/>
First production version: September 2017
First production version for CERNBox: September 2017 <br/>
Integration in the CS3 Organisation: April 2020
This project has been presented at the [ownCloud Conference 2017](https://occon17.owncloud.org).
Slides available at [slideshare.net](https://www.slideshare.net/giuseppelopresti/collaborative-editing-and-more-in-cernbox).
## Environment variables
A docker container is provided, which takes the following variables from the environment:
- __CONFIGURATION__ - HTTP URL pointing to the configuration files in your-personal-internal-area
- __OCSECRET__ - password between oc and wopiserver
- __WOPISECRET__ - password between wopiserver and oos

View File

@ -2,16 +2,15 @@
# cernbox-wopi-server spec file
#
Name: cernbox-wopi-server
Summary: A WOPI server to support Office online suites on CERNBox
Version: 4.2
Release: 4%{?dist}
Summary: A WOPI server to support Office online suites for the ScienceMesh IOP
Version: 5.0
Release: 0%{?dist}
License: GPLv3
Buildroot: %{_tmppath}/%{name}-buildroot
Group: CERN-IT/ST
BuildArch: noarch
Source: %{name}-%{version}.tar.gz
# The required Python version makes this package depend on Fedora 29 or similar recent distros to compile and run.
BuildRequires: python(abi) >= 3.6
Requires: python(abi) >= 3.6, python36-pip
# pip3-installed "Requires": python3-flask, python3-jwt, python3-pyOpenSSL, requests
@ -20,7 +19,10 @@ Requires: python(abi) >= 3.6, python36-pip
AutoReq: no
%description
This RPM provides a Flask-based web server to implement the WOPI protocol for CERNBox
This RPM provides a Flask-based reference implementation of the WOPI protocol for the CS3 ScienceMesh IOP.
Support for the IOP via CS3 APIs is being developed. The server supports local storage for testing purposes,
as well as legacy xrootd-based storages currently used in production at CERN for CERNBox.
# Don't do any post-install weirdness, especially compiling .py files
%define __os_install_post %{nil}
@ -60,7 +62,7 @@ rm -rf %buildroot/
%post
touch /etc/wopi/wopisecret
touch /etc/wopi/ocsecret
touch /etc/wopi/iopsecret
%files
%defattr(-,root,root,-)
@ -72,6 +74,10 @@ touch /etc/wopi/ocsecret
%_python_lib/*
%changelog
* Wed Apr 22 2020 Giuseppe Lo Presti <lopresti@cern.ch> 5.0
- General refactoring of the code base and evolution to
become fully vendor-neutral
- Moved to the CS3 Organisation
* Wed Apr 08 2020 Giuseppe Lo Presti <lopresti@cern.ch> 4.2
- Introduced two new lock-related endpoints to cover interoperability
with OnlyOffice

View File

@ -4,7 +4,7 @@
#
# This script can be used to generate a docker image of the WOPI server.
# Prior to run it, you need to collect here a valid wopiserver.conf and
# an ocsecret file that contains the shared secret used by your OwnCloud
# an iopsecret file that contains the shared secret used by your EFSS
# servers to authenticate to the WOPI server.
#
# If you want the WOPI server to run in secure mode, you need to generate

View File

@ -16,7 +16,7 @@ usehttps = no
# location of the secret files. Requires a restart of the
# WOPI server when either the files or their content change.
wopisecretfile = /etc/wopi/wopisecret
ocsecretfile = /etc/wopi/ocsecret
iopsecretfile = /etc/wopi/iopsecret
[local]
storagehomepath = /var/wopi_local_storage

View File

@ -3,7 +3,7 @@
echo "${WOPISECRET:-$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 12 | head -n 1)}" > /etc/wopi/wopisecret
#cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 12 | head -n 1 > /etc/wopi/wopisecret
echo "${OCSECRET:-password}" > /etc/wopi/ocsecret
echo "${IOPSECRET:-password}" > /etc/wopi/iopsecret
/usr/bin/curl -o /etc/wopi/wopiserver.conf ${CONFIGURATION}/wopi/wopiserver.conf

View File

@ -1,24 +1,24 @@
# Dockerfile for Wopi Server
# Dockerfile for WOPI Server
#
# Please, build and run via docker-compose file: wopiserver.yaml
#FROM cern/c8-base:latest # this will eventually be the default
#FROM python:3 # this will eventually be the default, but for now we need the yum infrastructure to install xrootd
FROM cern/cc7-base:latest
LABEL maintainer="cernbox-admins@cern.ch" name="wopiserver: The CERNBox WOPI server" version="1.0"
LABEL maintainer="cernbox-admins@cern.ch" name="The ScienceMesh IOP WOPI server" version="1.0"
MAINTAINER Michael D'Silva <md@aarnet.edu.au>, Giuseppe Lo Presti <lopresti@cern.ch>
MAINTAINER Giuseppe Lo Presti <lopresti@cern.ch>
ADD cernbox-wopi*rpm /tmp
RUN yum -y install \
sudo \
python36 \
python36-pip \
python36-devel \
openssl-devel \
xrootd-client \
python3-xrootd \
/tmp/cernbox-wopi*rpm
sudo \
python36 \
python36-pip \
python36-devel \
openssl-devel \
xrootd-client \
python3-xrootd \
/tmp/cernbox-wopi*rpm
RUN pip3 install flask pyOpenSSL PyJWT requests
@ -30,3 +30,4 @@ RUN chmod 777 /var/log/wopi
#CMD /scripts/entrypoint
CMD ["python3", "/usr/bin/wopiserver.py"]

View File

@ -1,2 +1,2 @@
curl --header "Authorization: Bearer "`cat /etc/wopi/ocsecret` https://`hostname`:8443/wopi/cbox/open/list
curl --header "Authorization: Bearer "`cat /etc/wopi/iopsecret` https://`hostname`:8443/wopi/cbox/open/list
echo

View File

@ -84,7 +84,7 @@ class Wopi:
cls.port = int(cls.config.get('general', 'port'))
cls.log.setLevel(cls.loglevels[cls.config.get('general', 'loglevel')])
cls.wopisecret = open(cls.config.get('security', 'wopisecretfile')).read().strip('\n')
cls.ocsecret = open(cls.config.get('security', 'ocsecretfile')).read().strip('\n')
cls.iopsecret = open(cls.config.get('security', 'iopsecretfile')).read().strip('\n')
cls.tokenvalidity = cls.config.getint('general', 'tokenvalidity')
storage.init(cls.config, cls.log) # initialize the xroot client module
cls.config.get('general', 'allowedclients') # read this to make sure it is configured
@ -456,7 +456,7 @@ def cboxOpen():
Wopi.refreshconfig()
req = flask.request
# if running in https mode, first check if the shared secret matches ours
if Wopi.useHttps and ('Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.ocsecret):
if Wopi.useHttps and ('Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.iopsecret):
Wopi.log.warning('msg="cboxOpen: unauthorized access attempt, missing authorization token" client="%s"' % req.remote_addr)
return 'Client not authorized', http.client.UNAUTHORIZED
# now validate the user identity and deny root access
@ -469,7 +469,7 @@ def cboxOpen():
Wopi.log.warning('msg="cboxOpen: invalid user/group in request" client="%s" user="%s:%s"' % \
(req.remote_addr, req.args['ruid'], req.args['rgid']))
return 'Client not authorized', http.client.UNAUTHORIZED
# then resolve the client: only our CERNBox/ownCloud servers shall use this API
# then resolve the client and reject unauthorized ones
allowedclients = Wopi.config.get('general', 'allowedclients').split()
for c in allowedclients:
try:
@ -533,7 +533,7 @@ def cboxDownload():
@Wopi.app.route("/wopi/cbox/endpoints", methods=['GET'])
def cboxEndPoints():
'''Returns the office apps end-points registered with this WOPI server. This is used by the OwnCloud
'''Returns the office apps end-points registered with this WOPI server. This is used by the EFSS
client to discover which Apps frontends can be used with this WOPI server.
Note that if the end-points are relocated and the corresponding configuration entry updated,
the WOPI server must be restarted.'''
@ -548,7 +548,7 @@ def cboxGetOpenFiles():
This call is protected by the same shared secret as the /wopi/cbox/open call.'''
req = flask.request
# first check if the shared secret matches ours
if 'Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.ocsecret:
if 'Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.iopsecret:
Wopi.log.warning('msg="cboxGetOpenFiles: unauthorized access attempt, missing authorization token" client="%s"' % req.remote_addr)
return 'Client not authorized', http.client.UNAUTHORIZED
# first convert the sets into lists, otherwise sets cannot be serialized in JSON format
@ -580,7 +580,7 @@ def cboxLock():
'''
req = flask.request
# first check if the shared secret matches ours
if 'Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.ocsecret:
if 'Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.iopsecret:
Wopi.log.warning('msg="cboxLock: unauthorized access attempt, missing authorization token" client="%s"' % req.remote_addr)
return 'Client not authorized', http.client.UNAUTHORIZED
filename = req.args['filename']
@ -658,7 +658,7 @@ def cboxUnlock():
'''
req = flask.request
# first check if the shared secret matches ours
if 'Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.ocsecret:
if 'Authorization' not in req.headers or req.headers['Authorization'] != 'Bearer ' + Wopi.iopsecret:
Wopi.log.warning('msg="cboxUnlock: unauthorized access attempt, missing authorization token" client="%s"' % req.remote_addr)
return 'Client not authorized', http.client.UNAUTHORIZED
filename = req.args['filename']
@ -728,12 +728,9 @@ def wopiCheckFileInfo(fileid):
(Wopi.config.get('general', 'downloadurl'), flask.request.args['access_token'])
filemd['HostViewUrl'] = '%s&%s' % (Wopi.ENDPOINTS[fExt]['view'], wopiSrc)
filemd['HostEditUrl'] = '%s&%s' % (Wopi.ENDPOINTS[fExt]['edit'], wopiSrc)
# the following is to enable the 'Edit in Word/Excel/PowerPoint' (desktop) action
# the following is to enable the 'Edit in Word/Excel/PowerPoint' (desktop) action (probably broken)
try:
# a path 'a-la owncloud' includes '/files/', which has to be stripped off.
# XXX This is temporary code for the AARNet config. Note this is not robust as a user path including '/files/' will be broken.
filemd['ClientUrl'] = Wopi.config.get('general', 'webdavurl') + '/' + \
(acctok['filename'].split("/files/", 1)[1] if '/files/' in acctok['filename'] else acctok['filename'])
filemd['ClientUrl'] = Wopi.config.get('general', 'webdavurl') + '/' + acctok['filename']
except configparser.NoOptionError:
# if no WebDAV URL is provided, ignore this setting
pass
@ -1100,7 +1097,7 @@ def wopiPutFile(fileid):
except IOError:
# either the file was deleted or it was updated/overwritten by others: force conflict
newname, ext = os.path.splitext(acctok['filename'])
# !!! note the OwnCloud format is '<filename>_conflict-<date>-<time>', but it is not synchronized back !!!
# !!! typical EFSS formats are like '<filename>_conflict-<date>-<time>', but they're not synchronized back !!!
newname = '%s-conflict-%s%s' % (newname, time.strftime('%Y%m%d-%H%M%S'), ext.strip())
_storeWopiFile(flask.request, acctok, newname)
# keep track of this action in the original file's xattr, to avoid looping (see below)
@ -1117,9 +1114,8 @@ def wopiPutFile(fileid):
(acctok['ruid'], acctok['rgid'], flask.request.args['access_token'], acctok['filename']))
return 'Conflicting copy already created', http.client.INTERNAL_SERVER_ERROR
# Go for overwriting the file. Note that the entire check+write operation should be atomic,
# but the previous check still gives the opportunity of a race condition. We just live with it
# as OwnCloud does not seem to provide anything better...
# Anyhow, previous versions are all stored and recoverable by the user.
# but the previous check still gives the opportunity of a race condition. We just live with it.
# Anyhow, the EFSS should support versioning for such cases.
_storeWopiFile(flask.request, acctok)
Wopi.log.info('msg="File successfully written" action="edit" user="%s:%s" filename="%s" token="%s"' % \
(acctok['ruid'], acctok['rgid'], acctok['filename'], flask.request.args['access_token'][-20:]))

View File

@ -65,7 +65,7 @@ lockrgid = 0
# Location of the secret files. Requires a restart of the
# WOPI server when either the files or their content change.
wopisecretfile = /etc/wopi/wopisecret
ocsecretfile = /etc/wopi/ocsecret
iopsecretfile = /etc/wopi/iopsecret
# Use https as opposed to http (requires certificate)
usehttps = no

View File

@ -1,5 +1,5 @@
[Unit]
Description=WOPI Server for CERNBox
Description=WOPI Server for Reva IOP
After=syslog.target
[Service]