diff options
| author | Vo Minh Thu <vmt@openerp.com> | 2011-09-08 14:38:18 +0200 |
|---|---|---|
| committer | Vo Minh Thu <vmt@openerp.com> | 2011-09-08 14:38:18 +0200 |
| commit | e643ffcc32485723cf0aaaee990bf7985cf9fce1 (patch) | |
| tree | 347a5e9878faafb187659ec301ec3d70b16035fc | |
| parent | 17c54e1217ec190bb145a32d7fddc2e53ca1f212 (diff) | |
[REF] websrv_lib:
- grouped together the concept of auth proxy and auth provider
- removed the sec_realms dictionary: it was redundant as the
auth proxy was set (in one of the implementation, not all) on
the handler by setupAuth. Now the auth proxy is always set on
the handler.
- reg_http_service accepts the argument of the HTTPDir
constructor.
bzr revid: vmt@openerp.com-20110908123818-suc53zebgv9kcy3c
| -rw-r--r-- | openerp/service/http_server.py | 66 | ||||
| -rw-r--r-- | openerp/service/web_services.py | 2 | ||||
| -rw-r--r-- | openerp/service/websrv_lib.py | 73 | ||||
| -rw-r--r-- | openerp/wsgi.py | 15 |
4 files changed, 48 insertions, 108 deletions
diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py index 8bf40024282..9bfb9397d19 100644 --- a/openerp/service/http_server.py +++ b/openerp/service/http_server.py @@ -250,14 +250,14 @@ class XMLRPCRequestHandler(FixSendError,HttpLogHandler,SimpleXMLRPCServer.Simple def init_xmlrpc(): if tools.config.get('xmlrpc', False): # Example of http file serving: - # reg_http_service(HTTPDir('/test/',HTTPHandler)) - reg_http_service(HTTPDir('/xmlrpc/', XMLRPCRequestHandler)) + # reg_http_service('/test/', HTTPHandler) + reg_http_service('/xmlrpc/', XMLRPCRequestHandler) logging.getLogger("web-services").info("Registered XML-RPC over HTTP") if tools.config.get('xmlrpcs', False) \ and not tools.config.get('xmlrpc', False): # only register at the secure server - reg_http_service(HTTPDir('/xmlrpc/', XMLRPCRequestHandler, secure_only=True)) + reg_http_service('/xmlrpc/', XMLRPCRequestHandler, secure_only=True) logging.getLogger("web-services").info("Registered XML-RPC over HTTPS only") class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler): @@ -299,23 +299,34 @@ def init_static_http(): base_path = tools.config.get('static_http_url_prefix', '/') - reg_http_service(HTTPDir(base_path,StaticHTTPHandler)) + reg_http_service(base_path, StaticHTTPHandler) logging.getLogger("web-services").info("Registered HTTP dir %s for %s" % \ (document_root, base_path)) -class OerpAuthProxy(AuthProxy): - """ Require basic authentication.. +import security - This is a copy of the BasicAuthProxy, which however checks/caches the db - as well. - """ - def __init__(self,provider): - AuthProxy.__init__(self,provider) +class OpenERPAuthProvider(AuthProvider): + """ Require basic authentication.""" + def __init__(self,realm='OpenERP User'): + self.realm = realm self.auth_creds = {} self.auth_tries = 0 self.last_auth = None + def authenticate(self, db, user, passwd, client_address): + try: + uid = security.login(db,user,passwd) + if uid is False: + return False + return (user, passwd, db, uid) + except Exception,e: + logging.getLogger("auth").debug("Fail auth: %s" % e ) + return False + + def log(self, msg, lvl=logging.INFO): + logging.getLogger("auth").log(lvl,msg) + def checkRequest(self,handler,path, db=False): auth_str = handler.headers.get('Authorization',False) try: @@ -329,46 +340,23 @@ class OerpAuthProxy(AuthProxy): db = psp[0] else: #FIXME! - self.provider.log("Wrong path: %s, failing auth" %path) + self.log("Wrong path: %s, failing auth" %path) raise AuthRejectedExc("Authorization failed. Wrong sub-path.") if self.auth_creds.get(db): return True if auth_str and auth_str.startswith('Basic '): auth_str=auth_str[len('Basic '):] (user,passwd) = base64.decodestring(auth_str).split(':') - self.provider.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db)) - acd = self.provider.authenticate(db,user,passwd,handler.client_address) + self.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db)) + acd = self.authenticate(db,user,passwd,handler.client_address) if acd != False: self.auth_creds[db] = acd self.last_auth = db return True if self.auth_tries > 5: - self.provider.log("Failing authorization after 5 requests w/o password") + self.log("Failing authorization after 5 requests w/o password") raise AuthRejectedExc("Authorization failed.") self.auth_tries += 1 - raise AuthRequiredExc(atype='Basic', realm=self.provider.realm) - -import security -class OpenERPAuthProvider(AuthProvider): - def __init__(self,realm='OpenERP User'): - self.realm = realm - - def setupAuth(self, multi, handler): - if not multi.sec_realms.has_key(self.realm): - multi.sec_realms[self.realm] = OerpAuthProxy(self) - handler.auth_proxy = multi.sec_realms[self.realm] - - def authenticate(self, db, user, passwd, client_address): - try: - uid = security.login(db,user,passwd) - if uid is False: - return False - return (user, passwd, db, uid) - except Exception,e: - logging.getLogger("auth").debug("Fail auth: %s" % e ) - return False - - def log(self, msg, lvl=logging.INFO): - logging.getLogger("auth").log(lvl,msg) + raise AuthRequiredExc(atype='Basic', realm=self.realm) #eof diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 8d05b5b776d..c941d3a809f 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -379,7 +379,7 @@ class common(netsvc.ExportService): return res or False elif method == 'logout': if auth: - auth.logout(params[1]) + auth.logout(params[1]) # TODO I didn't see any AuthProxy implementing this method. logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db)) return True elif method in ['about', 'timezone_get', 'get_server_environment', diff --git a/openerp/service/websrv_lib.py b/openerp/service/websrv_lib.py index 5b98714e80e..ac83cb893c0 100644 --- a/openerp/service/websrv_lib.py +++ b/openerp/service/websrv_lib.py @@ -52,61 +52,17 @@ class AuthProvider: def __init__(self,realm): self.realm = realm - def setupAuth(self, multi,handler): - """ Attach an AuthProxy object to handler - """ - pass - def authenticate(self, user, passwd, client_address): return False def log(self, msg): print msg -class BasicAuthProvider(AuthProvider): - def setupAuth(self, multi, handler): - if not multi.sec_realms.has_key(self.realm): - multi.sec_realms[self.realm] = BasicAuthProxy(self) - - -class AuthProxy: - """ This class will hold authentication information for a handler, - i.e. a connection - """ - def __init__(self, provider): - self.provider = provider - def checkRequest(self,handler,path = '/'): """ Check if we are allowed to process that request """ pass -class BasicAuthProxy(AuthProxy): - """ Require basic authentication.. - """ - def __init__(self,provider): - AuthProxy.__init__(self,provider) - self.auth_creds = None - self.auth_tries = 0 - - def checkRequest(self,handler,path = '/'): - if self.auth_creds: - return True - auth_str = handler.headers.get('Authorization',False) - if auth_str and auth_str.startswith('Basic '): - auth_str=auth_str[len('Basic '):] - (user,passwd) = base64.decodestring(auth_str).split(':') - self.provider.log("Found user=\"%s\", passwd=\"%s\"" %(user,passwd)) - self.auth_creds = self.provider.authenticate(user,passwd,handler.client_address) - if self.auth_creds: - return True - if self.auth_tries > 5: - self.provider.log("Failing authorization after 5 requests w/o password") - raise AuthRejectedExc("Authorization failed.") - self.auth_tries += 1 - raise AuthRequiredExc(atype = 'Basic', realm=self.provider.realm) - - class HTTPHandler(SimpleHTTPRequestHandler): def __init__(self,request, client_address, server): SimpleHTTPRequestHandler.__init__(self,request,client_address,server) @@ -144,13 +100,19 @@ class HTTPDir: return self.path return False -def reg_http_service(service): - """ Register some handler to httpd. - hts must be an HTTPDir + def instanciate_handler(self, request, client_address, server): + handler = self.handler(noconnection(request), client_address, server) + if self.auth_provider: + handler.auth_provider = self.auth_provider + return handler + +def reg_http_service(path, handler, auth_provider=None, secure_only=False): + """ Register a HTTP handler at a given path. + + The auth_provider will be set on the handler instances. """ - assert isinstance(service, HTTPDir), "Wrong class for http service" - global handlers + service = HTTPDir(path, handler, auth_provider, secure_only) pos = len(handlers) lastpos = pos while pos > 0: @@ -286,11 +248,10 @@ class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler): def __init__(self, request, client_address, server): self.in_handlers = {} - self.sec_realms = {} SocketServer.StreamRequestHandler.__init__(self,request,client_address,server) self.log_message("MultiHttpHandler init for %s" %(str(client_address))) - def _handle_one_foreign(self,fore, path, auth_provider): + def _handle_one_foreign(self, fore, path): """ This method overrides the handle_one_request for *children* handlers. It is required, since the first line should not be read again.. @@ -306,9 +267,9 @@ class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler): return self.request_version = fore.request_version - if auth_provider and auth_provider.realm: + if hasattr(fore, 'auth_provider'): try: - self.sec_realms[auth_provider.realm].checkRequest(fore,path) + fore.auth_provider.checkRequest(fore,path) except AuthRequiredExc,ae: # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the # authorisation features of HTTP/1.1 @@ -456,15 +417,13 @@ class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler): npath = '/' + npath if not self.in_handlers.has_key(p): - self.in_handlers[p] = vdir.handler(noconnection(self.request),self.client_address,self.server) - if vdir.auth_provider: - vdir.auth_provider.setupAuth(self, self.in_handlers[p]) + self.in_handlers[p] = vdir.instanciate_handler(noconnection(self.request),self.client_address,self.server) hnd = self.in_handlers[p] hnd.rfile = self.rfile hnd.wfile = self.wfile self.rlpath = self.raw_requestline try: - self._handle_one_foreign(hnd,npath, vdir.auth_provider) + self._handle_one_foreign(hnd, npath) except IOError, e: if e.errno == errno.EPIPE: self.log_message("Could not complete request %s," \ diff --git a/openerp/wsgi.py b/openerp/wsgi.py index ad36eb14c26..3519cdf4090 100644 --- a/openerp/wsgi.py +++ b/openerp/wsgi.py @@ -173,15 +173,8 @@ def http_to_wsgi(http_dir): server.server_port = int(environ['SERVER_PORT']) con = openerp.service.websrv_lib.noconnection(environ['gunicorn.socket']) # None TODO - # Let's pretend we have a Multi handler (i.e. the - # websrv_lib.MultiHTTPHandler class) to hand to the auth. provider. - multi = Dummy() - multi.sec_realms = {} - # Initialize the underlying handler and associated auth. provider. - handler = http_dir.handler(openerp.service.websrv_lib.noconnection(con), environ['REMOTE_ADDR'], server) - auth_provider = http_dir.auth_provider - auth_provider.setupAuth(multi, handler) + handler = http_dir.instanciate_handler(openerp.service.websrv_lib.noconnection(con), environ['REMOTE_ADDR'], server) # Populate the handler as if it is called by a regular HTTP server # and the request is already parsed. @@ -197,9 +190,9 @@ def http_to_wsgi(http_dir): # Handle authentication if there is an auth. provider associated to # the handler. - if auth_provider and auth_provider.realm: + if hasattr(handler, 'auth_provider'): try: - multi.sec_realms[auth_provider.realm].checkRequest(handler, path) + handler.auth_provider.checkRequest(handler, path) except websrv_lib.AuthRequiredExc, ae: # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the # authorisation features of HTTP/1.1 @@ -245,7 +238,7 @@ def http_to_wsgi(http_dir): except (websrv_lib.AuthRejectedExc, websrv_lib.AuthRequiredExc): raise except Exception, e: - start_response("500 Internal error") + start_response("500 Internal error", []) return [] return wsgi_handler |
