2010-03-04 09:03:42 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2009-08-29 15:23:46 +00:00
|
|
|
#
|
2010-07-26 09:33:36 +00:00
|
|
|
# Copyright P. Christeas <p_christ@hol.gr> 2008-2010
|
|
|
|
# Copyright 2010 OpenERP SA. (http://www.openerp.com)
|
2009-08-29 15:23:46 +00:00
|
|
|
#
|
|
|
|
#
|
|
|
|
# WARNING: This program as such is intended to be used by professional
|
2012-02-12 11:45:09 +00:00
|
|
|
# programmers who take the whole responsibility of assessing all potential
|
2009-08-29 15:23:46 +00:00
|
|
|
# consequences resulting from its eventual inadequacies and bugs
|
|
|
|
# End users who are looking for a ready-to-use solution with commercial
|
2012-02-12 11:45:09 +00:00
|
|
|
# guarantees and support are strongly advised to contract a Free Software
|
2009-08-29 15:23:46 +00:00
|
|
|
# Service Company
|
|
|
|
#
|
|
|
|
# This program is Free Software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU General Public License
|
|
|
|
# as published by the Free Software Foundation; either version 2
|
|
|
|
# of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
2013-05-14 14:29:26 +00:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2009-08-29 15:23:46 +00:00
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
2011-06-23 09:04:57 +00:00
|
|
|
""" This module offers the family of HTTP-based servers. These are not a single
|
|
|
|
class/functionality, but a set of network stack layers, implementing
|
|
|
|
extendable HTTP protocols.
|
2010-03-04 09:05:56 +00:00
|
|
|
|
2011-06-23 09:04:57 +00:00
|
|
|
The OpenERP server defines a single instance of a HTTP server, listening at
|
|
|
|
the standard 8069, 8071 ports (well, it is 2 servers, and ports are
|
|
|
|
configurable, of course). This "single" server then uses a `MultiHTTPHandler`
|
|
|
|
to dispatch requests to the appropriate channel protocol, like the XML-RPC,
|
|
|
|
static HTTP, DAV or other.
|
2009-08-29 15:23:46 +00:00
|
|
|
"""
|
2011-06-23 09:04:57 +00:00
|
|
|
|
2012-01-15 21:42:14 +00:00
|
|
|
import base64
|
2010-07-26 09:33:34 +00:00
|
|
|
import posixpath
|
|
|
|
import urllib
|
2009-08-29 15:23:46 +00:00
|
|
|
import os
|
2010-07-26 09:33:34 +00:00
|
|
|
import logging
|
2009-08-29 15:23:46 +00:00
|
|
|
|
2012-01-15 21:42:14 +00:00
|
|
|
from websrv_lib import *
|
|
|
|
import openerp.tools as tools
|
|
|
|
|
2009-08-29 15:23:46 +00:00
|
|
|
try:
|
|
|
|
import fcntl
|
|
|
|
except ImportError:
|
|
|
|
fcntl = None
|
2010-03-04 09:05:56 +00:00
|
|
|
|
2009-09-08 08:15:16 +00:00
|
|
|
try:
|
2009-11-24 14:44:05 +00:00
|
|
|
from ssl import SSLError
|
2009-09-08 08:15:16 +00:00
|
|
|
except ImportError:
|
2009-11-24 14:44:05 +00:00
|
|
|
class SSLError(Exception): pass
|
2009-08-29 15:23:46 +00:00
|
|
|
|
2012-01-24 15:07:50 +00:00
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
2012-02-07 21:46:04 +00:00
|
|
|
# TODO delete this for 6.2, it is still needed for 6.1.
|
|
|
|
class HttpLogHandler:
|
|
|
|
""" helper class for uniform log handling
|
|
|
|
Please define self._logger at each class that is derived from this
|
|
|
|
"""
|
|
|
|
_logger = None
|
|
|
|
|
|
|
|
def log_message(self, format, *args):
|
|
|
|
self._logger.debug(format % args) # todo: perhaps other level
|
|
|
|
|
|
|
|
def log_error(self, format, *args):
|
|
|
|
self._logger.error(format % args)
|
|
|
|
|
|
|
|
def log_exception(self, format, *args):
|
|
|
|
self._logger.exception(format, *args)
|
|
|
|
|
|
|
|
def log_request(self, code='-', size='-'):
|
|
|
|
self._logger.debug('"%s" %s %s',
|
|
|
|
self.requestline, str(code), str(size))
|
|
|
|
|
|
|
|
class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler):
|
|
|
|
_logger = logging.getLogger(__name__)
|
2009-08-29 15:23:46 +00:00
|
|
|
|
2011-09-25 01:20:39 +00:00
|
|
|
_HTTP_OPTIONS = { 'Allow': ['OPTIONS', 'GET', 'HEAD'] }
|
|
|
|
|
|
|
|
def __init__(self,request, client_address, server):
|
|
|
|
HTTPHandler.__init__(self,request,client_address,server)
|
|
|
|
document_root = tools.config.get('static_http_document_root', False)
|
|
|
|
assert document_root, "Please specify static_http_document_root in configuration, or disable static-httpd!"
|
|
|
|
self.__basepath = document_root
|
|
|
|
|
|
|
|
def translate_path(self, path):
|
|
|
|
"""Translate a /-separated PATH to the local filename syntax.
|
|
|
|
|
|
|
|
Components that mean special things to the local file system
|
|
|
|
(e.g. drive or directory names) are ignored. (XXX They should
|
|
|
|
probably be diagnosed.)
|
|
|
|
|
|
|
|
"""
|
|
|
|
# abandon query parameters
|
|
|
|
path = path.split('?',1)[0]
|
|
|
|
path = path.split('#',1)[0]
|
|
|
|
path = posixpath.normpath(urllib.unquote(path))
|
|
|
|
words = path.split('/')
|
|
|
|
words = filter(None, words)
|
|
|
|
path = self.__basepath
|
|
|
|
for word in words:
|
|
|
|
if word in (os.curdir, os.pardir): continue
|
|
|
|
path = os.path.join(path, word)
|
|
|
|
return path
|
|
|
|
|
|
|
|
def init_static_http():
|
|
|
|
if not tools.config.get('static_http_enable', False):
|
|
|
|
return
|
|
|
|
|
|
|
|
document_root = tools.config.get('static_http_document_root', False)
|
|
|
|
assert document_root, "Document root must be specified explicitly to enable static HTTP service (option --static-http-document-root)"
|
|
|
|
|
|
|
|
base_path = tools.config.get('static_http_url_prefix', '/')
|
|
|
|
|
|
|
|
reg_http_service(base_path, StaticHTTPHandler)
|
|
|
|
|
2012-01-24 15:07:50 +00:00
|
|
|
_logger.info("Registered HTTP dir %s for %s", document_root, base_path)
|
2011-09-25 01:20:39 +00:00
|
|
|
|
2011-09-08 12:38:18 +00:00
|
|
|
import security
|
2010-03-04 09:05:56 +00:00
|
|
|
|
2011-09-08 12:38:18 +00:00
|
|
|
class OpenERPAuthProvider(AuthProvider):
|
|
|
|
""" Require basic authentication."""
|
|
|
|
def __init__(self,realm='OpenERP User'):
|
|
|
|
self.realm = realm
|
2009-11-24 14:44:05 +00:00
|
|
|
self.auth_creds = {}
|
|
|
|
self.auth_tries = 0
|
|
|
|
self.last_auth = None
|
|
|
|
|
2011-09-08 12:38:18 +00:00
|
|
|
def authenticate(self, db, user, passwd, client_address):
|
|
|
|
try:
|
|
|
|
uid = security.login(db,user,passwd)
|
|
|
|
if uid is False:
|
|
|
|
return False
|
2012-12-14 12:38:03 +00:00
|
|
|
return user, passwd, db, uid
|
2011-09-08 12:38:18 +00:00
|
|
|
except Exception,e:
|
2012-01-24 15:07:50 +00:00
|
|
|
_logger.debug("Fail auth: %s" % e )
|
2011-09-08 12:38:18 +00:00
|
|
|
return False
|
|
|
|
|
2010-04-06 11:09:53 +00:00
|
|
|
def checkRequest(self,handler,path, db=False):
|
2009-11-24 14:44:05 +00:00
|
|
|
auth_str = handler.headers.get('Authorization',False)
|
|
|
|
try:
|
2010-04-06 11:09:53 +00:00
|
|
|
if not db:
|
|
|
|
db = handler.get_db_from_path(path)
|
2010-06-24 13:43:32 +00:00
|
|
|
except Exception:
|
2009-11-24 14:44:05 +00:00
|
|
|
if path.startswith('/'):
|
|
|
|
path = path[1:]
|
|
|
|
psp= path.split('/')
|
|
|
|
if len(psp)>1:
|
|
|
|
db = psp[0]
|
|
|
|
else:
|
|
|
|
#FIXME!
|
2012-01-25 12:51:51 +00:00
|
|
|
_logger.info("Wrong path: %s, failing auth" %path)
|
2010-04-06 11:09:53 +00:00
|
|
|
raise AuthRejectedExc("Authorization failed. Wrong sub-path.")
|
|
|
|
if self.auth_creds.get(db):
|
|
|
|
return True
|
2009-11-24 14:44:05 +00:00
|
|
|
if auth_str and auth_str.startswith('Basic '):
|
|
|
|
auth_str=auth_str[len('Basic '):]
|
|
|
|
(user,passwd) = base64.decodestring(auth_str).split(':')
|
2012-01-25 12:51:51 +00:00
|
|
|
_logger.info("Found user=\"%s\", passwd=\"***\" for db=\"%s\"", user, db)
|
2011-09-08 12:38:18 +00:00
|
|
|
acd = self.authenticate(db,user,passwd,handler.client_address)
|
2009-11-24 14:44:05 +00:00
|
|
|
if acd != False:
|
|
|
|
self.auth_creds[db] = acd
|
2010-04-06 11:09:53 +00:00
|
|
|
self.last_auth = db
|
2009-11-24 14:44:05 +00:00
|
|
|
return True
|
|
|
|
if self.auth_tries > 5:
|
2012-01-25 12:51:51 +00:00
|
|
|
_logger.info("Failing authorization after 5 requests w/o password")
|
2009-11-24 14:44:05 +00:00
|
|
|
raise AuthRejectedExc("Authorization failed.")
|
|
|
|
self.auth_tries += 1
|
2011-09-08 12:38:18 +00:00
|
|
|
raise AuthRequiredExc(atype='Basic', realm=self.realm)
|
2009-09-03 21:08:02 +00:00
|
|
|
|
2011-11-22 08:58:48 +00:00
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|