backport stable into default
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 16 Mar 2010 16:32:36 +0100
changeset 4914 dcb055f32d9b
parent 4913 083b4d454192 (current diff)
parent 4911 898c35be5873 (diff)
child 4915 d657b89df9f4
backport stable into default
etwist/server.py
web/application.py
web/views/basecontrollers.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
--- 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
--- 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):
--- 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]:
--- 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 :
--- 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 += '/'