# HG changeset patch # User Sylvain Thénault # Date 1268753556 -3600 # Node ID dcb055f32d9b4d34fb79ed4afe6bbd1157f10080 # Parent 083b4d45419297300de5db49380edfc9f5b314bd# Parent 898c35be58731f75c72663d65e486121d0a4284d backport stable into default diff -r 083b4d454192 -r dcb055f32d9b _exceptions.py --- a/_exceptions.py Mon Mar 01 11:26:14 2010 +0100 +++ b/_exceptions.py Tue Mar 16 16:32:36 2010 +0100 @@ -49,7 +49,11 @@ class AuthenticationError(ConnectionError): """raised when a bad connection id is given or when an attempt to establish - a connection failed""" + a connection failed + """ + def __init__(self, *args, **kwargs): + super(AuthenticationError, self).__init__(*args) + self.__dict__.update(kwargs) class BadConnectionId(ConnectionError): """raised when a bad connection id is given or when an attempt to establish diff -r 083b4d454192 -r dcb055f32d9b etwist/server.py --- a/etwist/server.py Mon Mar 01 11:26:14 2010 +0100 +++ b/etwist/server.py Tue Mar 16 16:32:36 2010 +0100 @@ -99,15 +99,11 @@ def __init__(self, config, debug=None): self.debugmode = debug self.config = config - self.base_url = config['base-url'] or config.default_base_url() - if self.base_url[-1] != '/': - self.base_url += '/' - self.https_url = config['https-url'] - if self.https_url and self.https_url[-1] != '/': - self.https_url += '/' # instantiate publisher here and not in init_publisher to get some # checks done before daemonization (eg versions consistency) self.appli = CubicWebPublisher(config, debug=self.debugmode) + self.base_url = config['base-url'] + self.https_url = config['https-url'] self.versioned_datadir = 'data%s' % config.instance_md5_version() def init_publisher(self): @@ -250,21 +246,12 @@ headers=req.headers_out or None) except ExplicitLogin: # must be before AuthenticationError return self.request_auth(req) - except AuthenticationError: - if self.config['auth-mode'] == 'cookie': - # in cookie mode redirecting to the index view is enough : - # either anonymous connection is allowed and the page will - # be displayed or we'll be redirected to the login form - msg = req._('you have been logged out') - if req.https: - req._base_url = self.base_url - req.https = False - url = req.build_url('view', vid='index', __message=msg) - return self.redirect(req, url) - else: - # in http we have to request auth to flush current http auth - # information - return self.request_auth(req, loggedout=True) + except AuthenticationError, ex: + if self.config['auth-mode'] == 'cookie' and getattr(ex, 'url', None): + return self.redirect(req, ex.url) + # in http we have to request auth to flush current http auth + # information + return self.request_auth(req, loggedout=True) except Redirect, ex: return self.redirect(req, ex.location) # request may be referenced by "onetime callback", so clear its entity diff -r 083b4d454192 -r dcb055f32d9b web/application.py --- a/web/application.py Mon Mar 01 11:26:14 2010 +0100 +++ b/web/application.py Tue Mar 16 16:32:36 2010 +0100 @@ -217,13 +217,13 @@ path = 'view' raise Redirect(req.build_url(path, **args)) - def logout(self, req): + def logout(self, req, goto_url): """logout from the instance by cleaning the session and raising `AuthenticationError` """ self.session_manager.close_session(req.cnx) req.remove_cookie(req.get_cookie(), self.SESSION_VAR) - raise AuthenticationError() + raise AuthenticationError(url=goto_url) class CubicWebPublisher(object): diff -r 083b4d454192 -r dcb055f32d9b web/views/authentication.py --- a/web/views/authentication.py Mon Mar 01 11:26:14 2010 +0100 +++ b/web/views/authentication.py Tue Mar 16 16:32:36 2010 +0100 @@ -39,19 +39,13 @@ __regid__ = 'loginpwdauth' order = 10 - def __init__(self, vreg): - self.anoninfo = vreg.config.anonymous_user() - def authentication_information(self, req): """retreive authentication information from the given request, raise NoAuthInfo if expected information is not found. """ login, password = req.get_authorization() if not login: - # No session and no login -> try anonymous - login, password = self.anoninfo - if not login: # anonymous not authorized - raise NoAuthInfo() + raise NoAuthInfo() return login, {'password': password} @@ -65,6 +59,7 @@ self.authinforetreivers = sorted(vreg['webauth'].possible_objects(vreg), key=lambda x: x.order) assert self.authinforetreivers + self.anoninfo = vreg.config.anonymous_user() def validate_session(self, req, session): """check session validity, and return eventually hijacked session @@ -116,37 +111,38 @@ continue try: cnx = self._authenticate(req, login, authinfo) - break except ExplicitLogin: continue # the next one may succeed + for retreiver_ in self.authinforetreivers: + retreiver_.authenticated(req, cnx, retreiver) + break else: - raise ExplicitLogin() - for retreiver_ in self.authinforetreivers: - retreiver_.authenticated(req, cnx, retreiver) + # false if no authentication info found, eg this is not an + # authentication failure + if 'login' in locals(): + req.set_message(req._('authentication failure')) + cnx = self._open_anonymous_connection(req) return cnx def _authenticate(self, req, login, authinfo): - # remove possibly cached cursor coming from closed connection cnxprops = ConnectionProperties(self.vreg.config.repo_method, close=False, log=self.log_queries) try: cnx = repo_connect(self.repo, login, cnxprops=cnxprops, **authinfo) except AuthenticationError: - req.set_message(req._('authentication failure')) - # restore an anonymous connection if possible - anonlogin, anonpassword = self.vreg.config.anonymous_user() - if anonlogin and anonlogin != login: - cnx = repo_connect(self.repo, anonlogin, password=anonpassword, - cnxprops=cnxprops) - self._init_cnx(cnx, anonlogin, {'password': anonpassword}) - else: - raise ExplicitLogin() - else: - self._init_cnx(cnx, login, authinfo) + raise ExplicitLogin() + self._init_cnx(cnx, login, authinfo) # associate the connection to the current request req.set_connection(cnx) return cnx + def _open_anonymous_connection(self, req): + # restore an anonymous connection if possible + login, password = self.anoninfo + if login: + return self._authenticate(req, login, {'password': password}) + raise ExplicitLogin() + def _init_cnx(self, cnx, login, authinfo): # decorate connection if login == self.vreg.config.anonymous_user()[0]: diff -r 083b4d454192 -r dcb055f32d9b web/views/basecontrollers.py --- a/web/views/basecontrollers.py Mon Mar 01 11:26:14 2010 +0100 +++ b/web/views/basecontrollers.py Tue Mar 16 16:32:36 2010 +0100 @@ -83,8 +83,19 @@ def publish(self, rset=None): """logout from the instance""" - return self.appli.session_handler.logout(self._cw) + return self.appli.session_handler.logout(self._cw, self.goto_url()) + def goto_url(self): + # * in http auth mode, url will be ignored + # * in cookie mode redirecting to the index view is enough : either + # anonymous connection is allowed and the page will be displayed or + # we'll be redirected to the login form + msg = self._cw._('you have been logged out') + if self._cw.https: + # XXX hack to generate an url on the http version of the site + self._cw._base_url = self._cw.vreg.config['base-url'] + self._cw.https = False + return self._cw.build_url('view', vid='index', __message=msg) class ViewController(Controller): """standard entry point : diff -r 083b4d454192 -r dcb055f32d9b web/webconfig.py --- a/web/webconfig.py Mon Mar 01 11:26:14 2010 +0100 +++ b/web/webconfig.py Tue Mar 16 16:32:36 2010 +0100 @@ -300,10 +300,10 @@ def _init_base_url(self): # normalize base url(s) - baseurl = self['base-url'] + baseurl = self['base-url'] or self.default_base_url() if baseurl and baseurl[-1] != '/': baseurl += '/' - self.global_set_option('base-url', baseurl) + self.global_set_option('base-url', baseurl) httpsurl = self['https-url'] if httpsurl and httpsurl[-1] != '/': httpsurl += '/'