1 # -*- coding: utf-8 -*-
3 # Copyright P. Christeas <p_christ@hol.gr> 2008-2010
4 # Copyright 2010 OpenERP SA. (http://www.openerp.com)
7 # WARNING: This program as such is intended to be used by professional
8 # programmers who take the whole responsability of assessing all potential
9 # consequences resulting from its eventual inadequacies and bugs
10 # End users who are looking for a ready-to-use solution with commercial
11 # garantees and support are strongly adviced to contract a Free Software
14 # This program is Free Software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ###############################################################################
29 #.apidoc title: HTTP and XML-RPC Server
31 """ This module offers the family of HTTP-based servers. These are not a single
32 class/functionality, but a set of network stack layers, implementing
33 extendable HTTP protocols.
35 The OpenERP server defines a single instance of a HTTP server, listening at
36 the standard 8069, 8071 ports (well, it is 2 servers, and ports are
37 configurable, of course). This "single" server then uses a `MultiHTTPHandler`
38 to dispatch requests to the appropriate channel protocol, like the XML-RPC,
39 static HTTP, DAV or other.
42 from websrv_lib import *
43 import openerp.netsvc as netsvc
46 import openerp.tools as tools
55 from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
63 from ssl import SSLError
65 class SSLError(Exception): pass
68 """ helper class for uniform log handling
69 Please define self._logger at each class that is derived from this
73 def log_message(self, format, *args):
74 self._logger.debug(format % args) # todo: perhaps other level
76 def log_error(self, format, *args):
77 self._logger.error(format % args)
79 def log_exception(self, format, *args):
80 self._logger.exception(format, *args)
82 def log_request(self, code='-', size='-'):
83 self._logger.log(netsvc.logging.DEBUG_RPC, '"%s" %s %s',
84 self.requestline, str(code), str(size))
86 class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler):
87 _logger = logging.getLogger('httpd')
88 _HTTP_OPTIONS = { 'Allow': ['OPTIONS', 'GET', 'HEAD'] }
90 def __init__(self,request, client_address, server):
91 HTTPHandler.__init__(self,request,client_address,server)
92 document_root = tools.config.get('static_http_document_root', False)
93 assert document_root, "Please specify static_http_document_root in configuration, or disable static-httpd!"
94 self.__basepath = document_root
96 def translate_path(self, path):
97 """Translate a /-separated PATH to the local filename syntax.
99 Components that mean special things to the local file system
100 (e.g. drive or directory names) are ignored. (XXX They should
101 probably be diagnosed.)
104 # abandon query parameters
105 path = path.split('?',1)[0]
106 path = path.split('#',1)[0]
107 path = posixpath.normpath(urllib.unquote(path))
108 words = path.split('/')
109 words = filter(None, words)
110 path = self.__basepath
112 if word in (os.curdir, os.pardir): continue
113 path = os.path.join(path, word)
116 def init_static_http():
117 if not tools.config.get('static_http_enable', False):
120 document_root = tools.config.get('static_http_document_root', False)
121 assert document_root, "Document root must be specified explicitly to enable static HTTP service (option --static-http-document-root)"
123 base_path = tools.config.get('static_http_url_prefix', '/')
125 reg_http_service(base_path, StaticHTTPHandler)
127 logging.getLogger("web-services").info("Registered HTTP dir %s for %s" % \
128 (document_root, base_path))
132 class OpenERPAuthProvider(AuthProvider):
133 """ Require basic authentication."""
134 def __init__(self,realm='OpenERP User'):
138 self.last_auth = None
140 def authenticate(self, db, user, passwd, client_address):
142 uid = security.login(db,user,passwd)
145 return (user, passwd, db, uid)
147 logging.getLogger("auth").debug("Fail auth: %s" % e )
150 def log(self, msg, lvl=logging.INFO):
151 logging.getLogger("auth").log(lvl,msg)
153 def checkRequest(self,handler,path, db=False):
154 auth_str = handler.headers.get('Authorization',False)
157 db = handler.get_db_from_path(path)
159 if path.startswith('/'):
166 self.log("Wrong path: %s, failing auth" %path)
167 raise AuthRejectedExc("Authorization failed. Wrong sub-path.")
168 if self.auth_creds.get(db):
170 if auth_str and auth_str.startswith('Basic '):
171 auth_str=auth_str[len('Basic '):]
172 (user,passwd) = base64.decodestring(auth_str).split(':')
173 self.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db))
174 acd = self.authenticate(db,user,passwd,handler.client_address)
176 self.auth_creds[db] = acd
179 if self.auth_tries > 5:
180 self.log("Failing authorization after 5 requests w/o password")
181 raise AuthRejectedExc("Authorization failed.")
183 raise AuthRequiredExc(atype='Basic', realm=self.realm)
187 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: