Add transactions support
[cascardo/ipsilon.git] / ipsilon / login / common.py
index f0efebd..f2254c9 100755 (executable)
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+from ipsilon.util.log import Log
 from ipsilon.util.page import Page
 from ipsilon.util.user import UserSession
 from ipsilon.util.plugin import PluginLoader, PluginObject
 from ipsilon.util.plugin import PluginInstaller
 from ipsilon.util.page import Page
 from ipsilon.util.user import UserSession
 from ipsilon.util.plugin import PluginLoader, PluginObject
 from ipsilon.util.plugin import PluginInstaller
+from ipsilon.info.common import Info
+from ipsilon.util.cookies import SecureCookie
 import cherrypy
 
 
 import cherrypy
 
 
-class LoginManagerBase(PluginObject):
+USERNAME_COOKIE = 'ipsilon_default_username'
+
+
+class LoginManagerBase(PluginObject, Log):
 
     def __init__(self):
         super(LoginManagerBase, self).__init__()
         self.path = '/'
         self.next_login = None
 
     def __init__(self):
         super(LoginManagerBase, self).__init__()
         self.path = '/'
         self.next_login = None
+        self.info = None
 
     def redirect_to_path(self, path):
         base = cherrypy.config.get('base.mount', "")
         raise cherrypy.HTTPRedirect('%s/login/%s' % (base, path))
 
 
     def redirect_to_path(self, path):
         base = cherrypy.config.get('base.mount', "")
         raise cherrypy.HTTPRedirect('%s/login/%s' % (base, path))
 
-    def auth_successful(self, username, userdata=None):
+    def auth_successful(self, username, auth_type=None, userdata=None):
         # save ref before calling UserSession login() as it
         # may regenerate the session
         session = UserSession()
         # save ref before calling UserSession login() as it
         # may regenerate the session
         session = UserSession()
@@ -43,12 +50,28 @@ class LoginManagerBase(PluginObject):
         if not ref:
             ref = cherrypy.config.get('base.mount', "") + '/'
 
         if not ref:
             ref = cherrypy.config.get('base.mount', "") + '/'
 
-        session.login(username)
-
-        # Save additional data provided by the login manager
-        if userdata:
-            for key in userdata:
-                session.save_data('user', key, userdata[key])
+        if self.info:
+            userattrs = self.info.get_user_attrs(username)
+            if userdata:
+                userdata.update(userattrs or {})
+            else:
+                userdata = userattrs
+            self.debug("User %s attributes: %s" % (username, repr(userdata)))
+
+        if auth_type:
+            if userdata:
+                userdata.update({'auth_type': auth_type})
+            else:
+                userdata = {'auth_type': auth_type}
+
+        session.login(username, userdata)
+
+        # save username into a cookie if parent was form base auth
+        if auth_type == 'password':
+            cookie = SecureCookie(USERNAME_COOKIE, username)
+            # 15 days
+            cookie.maxage = 1296000
+            cookie.send()
 
         raise cherrypy.HTTPRedirect(ref)
 
 
         raise cherrypy.HTTPRedirect(ref)
 
@@ -68,10 +91,6 @@ class LoginManagerBase(PluginObject):
 
         raise cherrypy.HTTPRedirect(ref)
 
 
         raise cherrypy.HTTPRedirect(ref)
 
-    def _debug(self, fact):
-        if cherrypy.config.get('debug', False):
-            cherrypy.log(fact)
-
     def get_tree(self, site):
         raise NotImplementedError
 
     def get_tree(self, site):
         raise NotImplementedError
 
@@ -103,12 +122,15 @@ class LoginManagerBase(PluginObject):
         plugins['enabled'].append(self)
         self._debug('Login plugin enabled: %s' % self.name)
 
         plugins['enabled'].append(self)
         self._debug('Login plugin enabled: %s' % self.name)
 
+        # Get handle of the info plugin
+        self.info = root.info
+
     def disable(self, site):
         plugins = site[FACILITY]
         if self not in plugins['enabled']:
             return
 
     def disable(self, site):
         plugins = site[FACILITY]
         if self not in plugins['enabled']:
             return
 
-        #remove self from chain
+        # remove self from chain
         root = plugins['root']
         if root.first_login == self:
             root.first_login = self.next_login
         root = plugins['root']
         if root.first_login == self:
             root.first_login = self.next_login
@@ -134,6 +156,48 @@ class LoginPageBase(Page):
         raise cherrypy.HTTPError(500)
 
 
         raise cherrypy.HTTPError(500)
 
 
+class LoginFormBase(LoginPageBase):
+
+    def __init__(self, site, mgr, page, template=None):
+        super(LoginFormBase, self).__init__(site, mgr)
+        self.formpage = page
+        self.formtemplate = template or 'login/form.html'
+
+    def GET(self, *args, **kwargs):
+        context = self.create_tmpl_context()
+        # pylint: disable=star-args
+        return self._template(self.formtemplate, **context)
+
+    def root(self, *args, **kwargs):
+        op = getattr(self, cherrypy.request.method, self.GET)
+        if callable(op):
+            return op(*args, **kwargs)
+
+    def create_tmpl_context(self, **kwargs):
+        next_url = None
+        if self.lm.next_login is not None:
+            next_url = self.lm.next_login.path
+
+        cookie = SecureCookie(USERNAME_COOKIE)
+        cookie.receive()
+        username = cookie.value
+        if username is None:
+            username = ''
+
+        context = {
+            "title": 'Login',
+            "action": '%s/%s' % (self.basepath, self.formpage),
+            "service_name": self.lm.service_name,
+            "username_text": self.lm.username_text,
+            "password_text": self.lm.password_text,
+            "description": self.lm.help_text,
+            "next_url": next_url,
+            "username": username,
+        }
+        context.update(kwargs)
+        return context
+
+
 FACILITY = 'login_config'
 
 
 FACILITY = 'login_config'
 
 
@@ -142,6 +206,7 @@ class Login(Page):
     def __init__(self, *args, **kwargs):
         super(Login, self).__init__(*args, **kwargs)
         self.first_login = None
     def __init__(self, *args, **kwargs):
         super(Login, self).__init__(*args, **kwargs)
         self.first_login = None
+        self.info = Info(self._site)
 
         loader = PluginLoader(Login, FACILITY, 'LoginManager')
         self._site[FACILITY] = loader.get_plugin_data()
 
         loader = PluginLoader(Login, FACILITY, 'LoginManager')
         self._site[FACILITY] = loader.get_plugin_data()