[web] disallow authenticated users to access to the login form (closes #914873)
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""user authentication component"""from__future__importwith_statement__docformat__="restructuredtext en"fromthreadingimportLockfromlogilab.common.decoratorsimportclear_cachefromcubicwebimportAuthenticationError,BadConnectionIdfromcubicweb.viewimportComponentfromcubicweb.dbapiimportrepo_connect,ConnectionPropertiesfromcubicweb.webimportInvalidSessionfromcubicweb.web.applicationimportAbstractAuthenticationManagerclassNoAuthInfo(Exception):passclassWebAuthInfoRetreiver(Component):__registry__='webauth'order=Nonedefauthentication_information(self,req):"""retreive authentication information from the given request, raise NoAuthInfo if expected information is not found. """raiseNotImplementedError()defauthenticated(self,retreiver,req,cnx,login,authinfo):"""callback when return authentication information have opened a repository connection successfully. Take care req has no session attached yet, hence req.execute isn't available. """passclassLoginPasswordRetreiver(WebAuthInfoRetreiver):__regid__='loginpwdauth'order=10defauthentication_information(self,req):"""retreive authentication information from the given request, raise NoAuthInfo if expected information is not found. """login,password=req.get_authorization()ifnotlogin:raiseNoAuthInfo()returnlogin,{'password':password}classRepositoryAuthenticationManager(AbstractAuthenticationManager):"""authenticate user associated to a request and check session validity"""def__init__(self,vreg):super(RepositoryAuthenticationManager,self).__init__(vreg)self.repo=vreg.config.repository(vreg)self.log_queries=vreg.config['query-log-file']self.authinforetreivers=sorted(vreg['webauth'].possible_objects(vreg),key=lambdax:x.order)# 2-uple login / password, login is None when no anonymous access# configuredself.anoninfo=vreg.config.anonymous_user()ifself.anoninfo[0]:self.anoninfo=(self.anoninfo[0],{'password':self.anoninfo[1]})defvalidate_session(self,req,session):"""check session validity, reconnecting it to the repository if the associated connection expired in the repository side (hence the necessity for this method). Return the connected user on success. raise :exc:`InvalidSession` if session is corrupted for a reason or another and should be closed """# with this authentication manager, session is actually a dbapi# connectionlogin=req.get_authorization()[0]# check session.login and not user.login, since in case of login by# email, login and cnx.login are the email while user.login is the# actual user loginifloginandsession.login!=login:raiseInvalidSession('login mismatch')try:lock=session.reconnection_lockexceptAttributeError:lock=session.reconnection_lock=Lock()# need to be locked two avoid duplicated reconnections on concurrent# requestswithlock:cnx=session.cnxtry:# calling cnx.user() check connection validity, raise# BadConnectionId on failureuser=cnx.user(req)exceptBadConnectionId:# check if a connection should be automatically restablishedif(loginisNoneorlogin==session.login):cnx=self._authenticate(session.login,session.authinfo)user=cnx.user(req)session.cnx=cnxelse:raiseInvalidSession('bad connection id')returnuserdefauthenticate(self,req):"""authenticate user using connection information found in the request, and return corresponding a :class:`~cubicweb.dbapi.Connection` instance, as well as login and authentication information dictionary used to open the connection. raise :exc:`cubicweb.AuthenticationError` if authentication failed (no authentication info found or wrong user/password) """forretreiverinself.authinforetreivers:try:login,authinfo=retreiver.authentication_information(req)exceptNoAuthInfo:continuetry:cnx=self._authenticate(login,authinfo)exceptAuthenticationError:continue# the next one may succeedforretreiver_inself.authinforetreivers:retreiver_.authenticated(retreiver,req,cnx,login,authinfo)returncnx,login,authinfo# false if no authentication info found, eg this is not an# authentication failureif'login'inlocals():req.set_message(req._('authentication failure'))login,authinfo=self.anoninfoiflogin:cnx=self._authenticate(login,authinfo)cnx.anonymous_connection=Truereturncnx,login,authinforaiseAuthenticationError()def_authenticate(self,login,authinfo):cnxprops=ConnectionProperties(self.vreg.config.repo_method,close=False,log=self.log_queries)cnx=repo_connect(self.repo,login,cnxprops=cnxprops,**authinfo)# decorate connectioncnx.vreg=self.vregreturncnx