Move user attribute storage into session functions
[cascardo/ipsilon.git] / ipsilon / login / common.py
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2013  Simo Sorce <simo@redhat.com>
4 #
5 # see file 'COPYING' for use and warranty information
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 from ipsilon.util.log import Log
21 from ipsilon.util.page import Page
22 from ipsilon.util.user import UserSession
23 from ipsilon.util.plugin import PluginLoader, PluginObject
24 from ipsilon.util.plugin import PluginInstaller
25 import cherrypy
26
27
28 class LoginManagerBase(PluginObject, Log):
29
30     def __init__(self):
31         super(LoginManagerBase, self).__init__()
32         self.path = '/'
33         self.next_login = None
34
35     def redirect_to_path(self, path):
36         base = cherrypy.config.get('base.mount', "")
37         raise cherrypy.HTTPRedirect('%s/login/%s' % (base, path))
38
39     def auth_successful(self, username, userdata=None):
40         # save ref before calling UserSession login() as it
41         # may regenerate the session
42         session = UserSession()
43         ref = session.get_data('login', 'Return')
44         if not ref:
45             ref = cherrypy.config.get('base.mount', "") + '/'
46
47         session.login(username, userdata)
48
49         raise cherrypy.HTTPRedirect(ref)
50
51     def auth_failed(self):
52         # try with next module
53         if self.next_login:
54             return self.redirect_to_path(self.next_login.path)
55
56         # return to the caller if any
57         session = UserSession()
58         ref = session.get_data('login', 'Return')
59
60         # otherwise destroy session and return error
61         if not ref:
62             session.logout(None)
63             raise cherrypy.HTTPError(401)
64
65         raise cherrypy.HTTPRedirect(ref)
66
67     def get_tree(self, site):
68         raise NotImplementedError
69
70     def enable(self, site):
71         plugins = site[FACILITY]
72         if self in plugins['enabled']:
73             return
74
75         # configure self
76         if self.name in plugins['config']:
77             self.set_config(plugins['config'][self.name])
78
79         # and add self to the root
80         root = plugins['root']
81         root.add_subtree(self.name, self.get_tree(site))
82
83         # finally add self in login chain
84         prev_obj = None
85         for prev_obj in plugins['enabled']:
86             if prev_obj.next_login:
87                 break
88         if prev_obj:
89             while prev_obj.next_login:
90                 prev_obj = prev_obj.next_login
91             prev_obj.next_login = self
92         if not root.first_login:
93             root.first_login = self
94
95         plugins['enabled'].append(self)
96         self._debug('Login plugin enabled: %s' % self.name)
97
98     def disable(self, site):
99         plugins = site[FACILITY]
100         if self not in plugins['enabled']:
101             return
102
103         # remove self from chain
104         root = plugins['root']
105         if root.first_login == self:
106             root.first_login = self.next_login
107         elif root.first_login:
108             prev_obj = root.first_login
109             while prev_obj.next_login != self:
110                 prev_obj = prev_obj.next_login
111             if prev_obj:
112                 prev_obj.next_login = self.next_login
113         self.next_login = None
114
115         plugins['enabled'].remove(self)
116         self._debug('Login plugin disabled: %s' % self.name)
117
118
119 class LoginPageBase(Page):
120
121     def __init__(self, site, mgr):
122         super(LoginPageBase, self).__init__(site)
123         self.lm = mgr
124
125     def root(self, *args, **kwargs):
126         raise cherrypy.HTTPError(500)
127
128
129 FACILITY = 'login_config'
130
131
132 class Login(Page):
133
134     def __init__(self, *args, **kwargs):
135         super(Login, self).__init__(*args, **kwargs)
136         self.first_login = None
137
138         loader = PluginLoader(Login, FACILITY, 'LoginManager')
139         self._site[FACILITY] = loader.get_plugin_data()
140         plugins = self._site[FACILITY]
141
142         available = plugins['available'].keys()
143         self._debug('Available login managers: %s' % str(available))
144
145         plugins['root'] = self
146         for item in plugins['whitelist']:
147             self._debug('Login plugin in whitelist: %s' % item)
148             if item not in plugins['available']:
149                 continue
150             plugins['available'][item].enable(self._site)
151
152     def add_subtree(self, name, page):
153         self.__dict__[name] = page
154
155     def root(self, *args, **kwargs):
156         if self.first_login:
157             raise cherrypy.HTTPRedirect('%s/login/%s' %
158                                         (self.basepath,
159                                          self.first_login.path))
160         return self._template('login/index.html', title='Login')
161
162
163 class Logout(Page):
164
165     def root(self, *args, **kwargs):
166         UserSession().logout(self.user)
167         return self._template('logout.html', title='Logout')
168
169
170 class LoginMgrsInstall(object):
171
172     def __init__(self):
173         pi = PluginInstaller(LoginMgrsInstall)
174         self.plugins = pi.get_plugins()