~ubuntu-branches/ubuntu/natty/tryton-server/natty-security

« back to all changes in this revision

Viewing changes to trytond/webdavsvc.py

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann, Daniel Baumann, Mathias Behrle
  • Date: 2009-04-21 19:27:00 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090421192700-hmiosex03jt5qf01
Tags: 1.2.0-1
[ Daniel Baumann ]
* Merging upstream version 1.2.0.
* Tidy rules files.
* Updating version information in manpage.
* Updating copyright file for new upstream release.
* Including TODO file in docs.

[ Mathias Behrle ]
* Updating application description.

[ Daniel Baumann ]
* Correcting wrapping of control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#This file is part of Tryton.  The COPYRIGHT file at the top level of
2
 
#this repository contains the full copyright notices and license terms.
3
 
import urlparse
4
 
import socket
5
 
import base64
6
 
import time
7
 
from DAV import AuthServer, WebDAVServer, iface
8
 
from DAV.errors import *
9
 
from DAV.constants import COLLECTION, OBJECT
10
 
from DAV.utils import get_uriparentpath, get_urifilename, quote_uri
11
 
from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree
12
 
from netsvc import LocalService, SSLSocket
13
 
import security
14
 
import pooler
15
 
from version import PACKAGE, VERSION, WEBSITE
16
 
from tools.misc import Cache
17
 
 
18
 
# Local int for multi-thread
19
 
import sys
20
 
if sys.version_info[:2] < (2, 4):
21
 
    from threadinglocal import local
22
 
else:
23
 
    from threading import local
24
 
 
25
 
 
26
 
class LocalInt(local):
27
 
 
28
 
    def __init__(self, value=0):
29
 
        self.value = value
30
 
 
31
 
    def __int__(self):
32
 
        return int(self.value)
33
 
 
34
 
USER_ID = LocalInt(0)
35
 
 
36
 
# Fix for bad use of Document in DAV.utils make_xmlresponse
37
 
from DAV.utils import VERSION as DAV_VERSION
38
 
if DAV_VERSION == '0.6':
39
 
    from xml.dom.Document import Document
40
 
    Document.Document = Document
41
 
 
42
 
# Fix for unset _config in DAVRequestHandler
43
 
if DAV_VERSION == '0.8':
44
 
 
45
 
 
46
 
    class DAV:
47
 
        lockemulation = False
48
 
        verbose = False
49
 
 
50
 
 
51
 
    class _Config:
52
 
        DAV = DAV()
53
 
 
54
 
    WebDAVServer.DAVRequestHandler._config = _Config()
55
 
 
56
 
 
57
 
class TrytonDAVInterface(iface.dav_interface):
58
 
 
59
 
    def __init__(self, interface, port, secure=False):
60
 
        if secure:
61
 
            protocol = 'https'
62
 
        else:
63
 
            protocol = 'http'
64
 
        self.baseuri = '%s://%s:%s/' % (protocol, interface or socket.gethostname(), port)
65
 
        self.verbose = False
66
 
 
67
 
    def _get_dburi(self, uri):
68
 
        uri = urlparse.urlsplit(uri)[2]
69
 
        if uri[0] == '/':
70
 
            uri = uri[1:]
71
 
        dbname, uri = (uri.split('/', 1) + [None])[0:2]
72
 
        return dbname, uri
73
 
 
74
 
    def get_childs(self, uri):
75
 
        res = []
76
 
        dbname, dburi = self._get_dburi(uri)
77
 
        if not dbname:
78
 
            db = LocalService('db')
79
 
            for dbname in db.list():
80
 
                res.append(urlparse.urljoin(self.baseuri, dbname))
81
 
            return res
82
 
        pool = pooler.get_pool(dbname)
83
 
        cursor = pooler.get_db(dbname).cursor()
84
 
        collection_obj = pool.get('webdav.collection')
85
 
        if uri[-1:] != '/':
86
 
            uri += '/'
87
 
        for child in collection_obj.get_childs(cursor, int(USER_ID), dburi):
88
 
            res.append(urlparse.urljoin(self.baseuri, uri + child))
89
 
        cursor.close()
90
 
        return res
91
 
 
92
 
    def get_data(self, uri):
93
 
        dbname, dburi = self._get_dburi(uri)
94
 
        if not dbname or (self.exists(uri) and self.is_collection(uri)):
95
 
            res = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'
96
 
            res += '<html>'
97
 
            res += '<head>'
98
 
            res += '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
99
 
            res += '<title>%s - WebDAV - %s</title>' \
100
 
                    % (PACKAGE, dbname or 'root')
101
 
            res += '</head>'
102
 
            res += '<body>'
103
 
            res += '<h2>Collection: %s</h2>' % (get_urifilename(uri) or '/')
104
 
            res += '<ul>'
105
 
            if dbname:
106
 
                res += '<li><a href="%s">..</a></li>' \
107
 
                        % (quote_uri(get_uriparentpath(uri) or '/'))
108
 
            childs = self.get_childs(uri)
109
 
            childs.sort()
110
 
            for child in childs:
111
 
                res += '<li><a href="%s">%s</a></li>' \
112
 
                        % (quote_uri(child), get_urifilename(child))
113
 
            res += '</ul>'
114
 
            res += '<hr noshade>'
115
 
            res += '<em>Powered by <a href="%s">%s</a> version %s</em>' \
116
 
                    % (quote_uri(WEBSITE), PACKAGE, VERSION)
117
 
            res += '</body>'
118
 
            res += '</html>'
119
 
            return res
120
 
        pool = pooler.get_pool(dbname)
121
 
        cursor = pooler.get_db(dbname).cursor()
122
 
        collection_obj = pool.get('webdav.collection')
123
 
        try:
124
 
            res = collection_obj.get_data(cursor, int(USER_ID), dburi)
125
 
        finally:
126
 
            cursor.close()
127
 
        return res
128
 
 
129
 
    def put(self, uri, data, content_type=''):
130
 
        dbname, dburi = self._get_dburi(uri)
131
 
        if not dbname or not dburi:
132
 
            raise DAV_Forbidden
133
 
        pool = pooler.get_pool(dbname)
134
 
        cursor = pooler.get_db(dbname).cursor()
135
 
        collection_obj = pool.get('webdav.collection')
136
 
        try:
137
 
            try:
138
 
                res = collection_obj.put(cursor, int(USER_ID), dburi, data,
139
 
                        content_type)
140
 
                cursor.commit()
141
 
            except:
142
 
                cursor.rollback()
143
 
                raise
144
 
        finally:
145
 
            cursor.close()
146
 
        return res
147
 
 
148
 
    def mkcol(self, uri):
149
 
        dbname, dburi = self._get_dburi(uri)
150
 
        if not dbname or not dburi:
151
 
            raise DAV_Forbidden
152
 
        pool = pooler.get_pool(dbname)
153
 
        cursor = pooler.get_db(dbname).cursor()
154
 
        collection_obj = pool.get('webdav.collection')
155
 
        try:
156
 
            try:
157
 
                res = collection_obj.mkcol(cursor, int(USER_ID), dburi)
158
 
                cursor.commit()
159
 
            except:
160
 
                cursor.rollback()
161
 
                raise
162
 
        finally:
163
 
            cursor.close()
164
 
        return res
165
 
 
166
 
    def _get_dav_resourcetype(self, uri):
167
 
        dbname, dburi = self._get_dburi(uri)
168
 
        if not dbname or not dburi:
169
 
            return COLLECTION
170
 
        pool = pooler.get_pool(dbname)
171
 
        cursor = pooler.get_db(dbname).cursor()
172
 
        collection_obj = pool.get('webdav.collection')
173
 
        res = collection_obj.get_resourcetype(cursor, int(USER_ID), dburi)
174
 
        cursor.close()
175
 
        return res
176
 
 
177
 
    def _get_dav_displayname(self, uri):
178
 
        raise DAV_Secret
179
 
 
180
 
    def _get_dav_getcontentlength(self, uri):
181
 
        dbname, dburi = self._get_dburi(uri)
182
 
        if not dbname or not dburi:
183
 
            return '0'
184
 
        pool = pooler.get_pool(dbname)
185
 
        cursor = pooler.get_db(dbname).cursor()
186
 
        collection_obj = pool.get('webdav.collection')
187
 
        res = collection_obj.get_contentlength(cursor, int(USER_ID), dburi)
188
 
        cursor.close()
189
 
        return res
190
 
 
191
 
    def _get_dav_getcontenttype(self, uri):
192
 
        dbname, dburi = self._get_dburi(uri)
193
 
        if not dbname or self.is_collection(uri):
194
 
            return "text/html"
195
 
        pool = pooler.get_pool(dbname)
196
 
        cursor = pooler.get_db(dbname).cursor()
197
 
        collection_obj = pool.get('webdav.collection')
198
 
        res = collection_obj.get_contenttype(cursor, int(USER_ID), dburi)
199
 
        cursor.close()
200
 
        return res
201
 
 
202
 
    def get_creationdate(self, uri):
203
 
        dbname, dburi = self._get_dburi(uri)
204
 
        if not dbname or not dburi:
205
 
            return time.time()
206
 
        pool = pooler.get_pool(dbname)
207
 
        cursor = pooler.get_db(dbname).cursor()
208
 
        collection_obj = pool.get('webdav.collection')
209
 
        res = collection_obj.get_creationdate(cursor, int(USER_ID), dburi)
210
 
        cursor.close()
211
 
        return res
212
 
 
213
 
    def get_lastmodified(self, uri):
214
 
        dbname, dburi = self._get_dburi(uri)
215
 
        if not dbname or not dburi:
216
 
            return time.time()
217
 
        pool = pooler.get_pool(dbname)
218
 
        cursor = pooler.get_db(dbname).cursor()
219
 
        collection_obj = pool.get('webdav.collection')
220
 
        res = collection_obj.get_lastmodified(cursor, int(USER_ID), dburi)
221
 
        cursor.close()
222
 
        return res
223
 
 
224
 
    def rmcol(self, uri):
225
 
        dbname, dburi = self._get_dburi(uri)
226
 
        if not dbname or not dburi:
227
 
            raise DAV_Forbidden
228
 
        pool = pooler.get_pool(dbname)
229
 
        cursor = pooler.get_db(dbname).cursor()
230
 
        collection_obj = pool.get('webdav.collection')
231
 
        try:
232
 
            try:
233
 
                res = collection_obj.rmcol(cursor, int(USER_ID), dburi)
234
 
                cursor.commit()
235
 
            except:
236
 
                cursor.rollback()
237
 
                raise
238
 
        finally:
239
 
            cursor.close()
240
 
        return res
241
 
 
242
 
    def rm(self, uri):
243
 
        dbname, dburi = self._get_dburi(uri)
244
 
        if not dbname or not dburi:
245
 
            raise DAV_Forbidden
246
 
        pool = pooler.get_pool(dbname)
247
 
        cursor = pooler.get_db(dbname).cursor()
248
 
        collection_obj = pool.get('webdav.collection')
249
 
        try:
250
 
            try:
251
 
                res = collection_obj.rm(cursor, int(USER_ID), dburi)
252
 
                cursor.commit()
253
 
            except:
254
 
                cursor.rollback()
255
 
                raise
256
 
        finally:
257
 
            cursor.close()
258
 
        return res
259
 
 
260
 
    def exists(self, uri):
261
 
        dbname, dburi = self._get_dburi(uri)
262
 
        if not dbname or not dburi:
263
 
            return 1
264
 
        pool = pooler.get_pool(dbname)
265
 
        cursor = pooler.get_db(dbname).cursor()
266
 
        collection_obj = pool.get('webdav.collection')
267
 
        res = collection_obj.exists(cursor, int(USER_ID), dburi)
268
 
        cursor.close()
269
 
        return res
270
 
 
271
 
    def is_collection(self, uri):
272
 
        if self._get_dav_resourcetype(uri) == COLLECTION:
273
 
            return 1
274
 
        return 0
275
 
 
276
 
    def copyone(self, src, dst, overwrite):
277
 
        return copyone(self, src, dst, overwrite)
278
 
 
279
 
    def copytree(self, src, dst, overwrite):
280
 
        return copytree(self, src, dst, overwrite)
281
 
 
282
 
    def moveone(self, src, dst, overwrite):
283
 
        return moveone(self, src, dst, overwrite)
284
 
 
285
 
    def movetree(self, src, dst, overwrite):
286
 
        return movetree(self, src, dst, overwrite)
287
 
 
288
 
    def delone(self, uri):
289
 
        return delone(self, uri)
290
 
 
291
 
    def deltree(self, uri):
292
 
        return deltree(self, uri)
293
 
 
294
 
    def copy(self, src, dst):
295
 
        content = self._get_dav_getcontenttype(src)
296
 
        data = self.get_data(src)
297
 
        self.put(dst, data, content)
298
 
        return 201
299
 
 
300
 
    def copycol(self, src, dst):
301
 
        return self.mkcol(dst)
302
 
 
303
 
 
304
 
class WebDAVAuthRequestHandler(AuthServer.BufferedAuthRequestHandler,
305
 
        WebDAVServer.DAVRequestHandler):
306
 
 
307
 
    def get_userinfo(self, user, password, command=''):
308
 
        global USER_ID
309
 
        dbname = self.path.split('/', 2)[1]
310
 
        if not dbname:
311
 
            return 1
312
 
        USER_ID = security.login(dbname, user, password, cache=False)
313
 
        Cache.clean(dbname)
314
 
        Cache.resets(dbname)
315
 
        if int(USER_ID):
316
 
            return 1
317
 
        return 0
318
 
 
319
 
class SecureWebDAVAuthRequestHandler(WebDAVAuthRequestHandler):
320
 
 
321
 
    def setup(self):
322
 
        self.connection = SSLSocket(self.request)
323
 
        self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
324
 
        self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)