# HG changeset patch # User Pierre-Yves David # Date 1331829751 -3600 # Node ID 76a44a0d7f4b4784d0b82108e1256b1040eb7f23 # Parent 87f2f18a77efb7335eeee09723bf96656e1bd21b [login] split authentication logic from post authentication logic (closes #2200755) * The Session manager is now only in charge of providing a valid session. * LoginControllers are now used in all case but wrong credential. * The LoginControllers are in charge of redirecting the user to the page wanted to see in the first place, expected to see. * The login form is now always submitted to the login controller with an extra argument pointing to the url we should redirect too after successful authentication. The ``"log out first logic"`` logic on login controller is removed because: 1. Other web actor do not do that. 2. Removed code do not need to be reimplemented. 3. We can only get it to work again in a single case: use do a GET request on http://www.my-cw-stuff.io/login 4. I do not see it's purpose. diff -r 87f2f18a77ef -r 76a44a0d7f4b devtools/testlib.py --- a/devtools/testlib.py Thu Mar 01 12:08:35 2012 +0100 +++ b/devtools/testlib.py Thu Mar 15 17:42:31 2012 +0100 @@ -697,13 +697,11 @@ def assertAuthSuccess(self, req, origsession, nbsessions=1): sh = self.app.session_handler - path, params = self.expect_redirect(lambda x: self.app.connect(x), req) + self.app.connect(req) session = req.session self.assertEqual(len(self.open_sessions), nbsessions, self.open_sessions) self.assertEqual(session.login, origsession.login) self.assertEqual(session.anonymous_session, False) - self.assertEqual(path, 'view') - self.assertMessageEqual(req, params, 'welcome %s !' % req.user.login) def assertAuthFailure(self, req, nbsessions=0): self.app.connect(req) diff -r 87f2f18a77ef -r 76a44a0d7f4b web/application.py --- a/web/application.py Thu Mar 01 12:08:35 2012 +0100 +++ b/web/application.py Thu Mar 15 17:42:31 2012 +0100 @@ -361,8 +361,6 @@ controller = self.vreg['controllers'].select(ctrlid, req, appli=self) except NoSelectableObject: - if ctrlid == 'login': - raise Unauthorized(req._('log out first')) raise Unauthorized(req._('not authorized')) req.update_search_state() result = controller.publish(rset=rset) diff -r 87f2f18a77ef -r 76a44a0d7f4b web/test/unittest_application.py --- a/web/test/unittest_application.py Thu Mar 01 12:08:35 2012 +0100 +++ b/web/test/unittest_application.py Thu Mar 15 17:42:31 2012 +0100 @@ -308,12 +308,6 @@ self.commit() self.assertEqual(vreg.property_value('ui.language'), 'en') - def test_login_not_available_to_authenticated(self): - req = self.request() - with self.assertRaises(Unauthorized) as cm: - self.app_publish(req, 'login') - self.assertEqual(str(cm.exception), 'log out first') - def test_fb_login_concept(self): """see data/views.py""" self.set_auth_mode('cookie', 'anon') @@ -343,7 +337,10 @@ def test_cookie_auth_no_anon(self): req, origsession = self.init_authentication('cookie') self.assertAuthFailure(req) - form = self.app_publish(req, 'login') + try: + form = self.app_publish(req, 'login') + except Redirect, redir: + self.fail('anonymous user should get login form') self.assertTrue('__login' in form) self.assertTrue('__password' in form) self.assertEqual(req.cnx, None) diff -r 87f2f18a77ef -r 76a44a0d7f4b web/test/unittest_views_basecontrollers.py --- a/web/test/unittest_views_basecontrollers.py Thu Mar 01 12:08:35 2012 +0100 +++ b/web/test/unittest_views_basecontrollers.py Thu Mar 15 17:42:31 2012 +0100 @@ -776,9 +776,6 @@ self.assertEqual(res, '12') - - - class UndoControllerTC(CubicWebTC): def setup_database(self): @@ -836,5 +833,20 @@ self.assertURLPath(cm.exception.location, 'toto') +class LoginControllerTC(CubicWebTC): + + def test_login_with_dest(self): + req = self.request() + req.form = {'postlogin_path': '/elephants/babar'} + with self.assertRaises(Redirect) as cm: + self.ctrl_publish(req, ctrl='login') + self.assertEqual('/elephants/babar', cm.exception.location) + + def test_login_no_dest(self): + req = self.request() + with self.assertRaises(Redirect) as cm: + self.ctrl_publish(req, ctrl='login') + self.assertEqual('/', cm.exception.location) + if __name__ == '__main__': unittest_main() diff -r 87f2f18a77ef -r 76a44a0d7f4b web/views/basecontrollers.py --- a/web/views/basecontrollers.py Thu Mar 01 12:08:35 2012 +0100 +++ b/web/views/basecontrollers.py Thu Mar 15 17:42:31 2012 +0100 @@ -84,6 +84,17 @@ # Cookie authentication return self.appli.need_login_content(self._cw) +class LoginControllerForAuthed(Controller): + __regid__ = 'login' + __select__ = ~anonymous_user() + + def publish(self, rset=None): + """log in the instance""" + path = self._cw.form.get('postlogin_path') + if not path: + path = '/' + raise Redirect(path) + class LogoutController(Controller): __regid__ = 'logout' diff -r 87f2f18a77ef -r 76a44a0d7f4b web/views/basetemplates.py --- a/web/views/basetemplates.py Thu Mar 01 12:08:35 2012 +0100 +++ b/web/views/basetemplates.py Thu Mar 15 17:42:31 2012 +0100 @@ -447,7 +447,11 @@ def form_action(self): if self.action is None: - return login_form_url(self._cw) + # reuse existing redirection if it exist + target = self._cw.form.get('postlogin_path', + self._cw.relative_path()) + return self._cw.build_url('login', __secure__=True, + postlogin_path=target) return super(LogForm, self).form_action() class LogForm(BaseLogForm): @@ -507,12 +511,3 @@ cw.html_headers.add_onload('jQuery("#__login:visible").focus()') LogFormTemplate = class_renamed('LogFormTemplate', LogFormView) - - -def login_form_url(req): - if req.https: - return req.url() - httpsurl = req.vreg.config.get('https-url') - if httpsurl: - return req.url().replace(req.base_url(), httpsurl) - return req.url() diff -r 87f2f18a77ef -r 76a44a0d7f4b web/views/sessions.py --- a/web/views/sessions.py Thu Mar 01 12:08:35 2012 +0100 +++ b/web/views/sessions.py Thu Mar 15 17:42:31 2012 +0100 @@ -95,18 +95,6 @@ # reopening. Is it actually a problem? if 'last_login_time' in req.vreg.schema: self._update_last_login_time(req) - args = req.form - for forminternal_key in ('__form_id', '__domid', '__errorurl'): - args.pop(forminternal_key, None) - path = req.relative_path(False) - if path in ('login', 'logout') or req.form.get('vid') == 'loggedout': - path = 'view' - args['__message'] = req._('welcome %s !') % req.user.login - if 'vid' in req.form and req.form['vid'] != 'loggedout': - args['vid'] = req.form['vid'] - if 'rql' in req.form: - args['rql'] = req.form['rql'] - raise Redirect(req.build_url(path, **args)) req.set_message(req._('welcome %s !') % req.user.login) def _update_last_login_time(self, req):