acd6d941dd9859454ecacdaf1a0ccda3ac934e14
[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)
48
49         # Save additional data provided by the login manager
50         if userdata:
51             for key in userdata:
52                 session.save_data('user', key, userdata[key])
53
54         raise cherrypy.HTTPRedirect(ref)
55
56     def auth_failed(self):
57         # try with next module
58         if self.next_login:
59             return self.redirect_to_path(self.next_login.path)
60
61         # return to the caller if any
62         session = UserSession()
63         ref = session.get_data('login', 'Return')
64
65         # otherwise destroy session and return error
66         if not ref:
67             session.logout(None)
68             raise cherrypy.HTTPError(401)
69
70         raise cherrypy.HTTPRedirect(ref)
71
72     def get_tree(self, site):
73         raise NotImplementedError
74
75     def enable(self, site):
76         plugins = site[FACILITY]
77         if self in plugins['enabled']:
78             return
79
80         # configure self
81         if self.name in plugins['config']:
82             self.set_config(plugins['config'][self.name])
83
84         # and add self to the root
85         root = plugins['root']
86         root.add_subtree(self.name, self.get_tree(site))
87
88         # finally add self in login chain
89         prev_obj = None
90         for prev_obj in plugins['enabled']:
91             if prev_obj.next_login:
92                 break
93         if prev_obj:
94             while prev_obj.next_login:
95                 prev_obj = prev_obj.next_login
96             prev_obj.next_login = self
97         if not root.first_login:
98             root.first_login = self
99
100         plugins['enabled'].append(self)
101         self._debug('Login plugin enabled: %s' % self.name)
102
103     def disable(self, site):
104         plugins = site[FACILITY]
105         if self not in plugins['enabled']:
106             return
107
108         # remove self from chain
109         root = plugins['root']
110         if root.first_login == self:
111             root.first_login = self.next_login
112         elif root.first_login:
113             prev_obj = root.first_login
114             while prev_obj.next_login != self:
115                 prev_obj = prev_obj.next_login
116             if prev_obj:
117                 prev_obj.next_login = self.next_login
118         self.next_login = None
119
120         plugins['enabled'].remove(self)
121         self._debug('Login plugin disabled: %s' % self.name)
122
123
124 class LoginPageBase(Page):
125
126     def __init__(self, site, mgr):
127         super(LoginPageBase, self).__init__(site)
128         self.lm = mgr
129
130     def root(self, *args, **kwargs):
131         raise cherrypy.HTTPError(500)
132
133
134 FACILITY = 'login_config'
135
136
137 class Login(Page):
138
139     def __init__(self, *args, **kwargs):
140         super(Login, self).__init__(*args, **kwargs)
141         self.first_login = None
142
143         loader = PluginLoader(Login, FACILITY, 'LoginManager')
144         self._site[FACILITY] = loader.get_plugin_data()
145         plugins = self._site[FACILITY]
146
147         available = plugins['available'].keys()
148         self._debug('Available login managers: %s' % str(available))
149
150         plugins['root'] = self
151         for item in plugins['whitelist']:
152             self._debug('Login plugin in whitelist: %s' % item)
153             if item not in plugins['available']:
154                 continue
155             plugins['available'][item].enable(self._site)
156
157     def add_subtree(self, name, page):
158         self.__dict__[name] = page
159
160     def root(self, *args, **kwargs):
161         if self.first_login:
162             raise cherrypy.HTTPRedirect('%s/login/%s' %
163                                         (self.basepath,
164                                          self.first_login.path))
165         return self._template('login/index.html', title='Login')
166
167
168 class Logout(Page):
169
170     def root(self, *args, **kwargs):
171         UserSession().logout(self.user)
172         return self._template('logout.html', title='Logout')
173
174
175 class LoginMgrsInstall(object):
176
177     def __init__(self):
178         pi = PluginInstaller(LoginMgrsInstall)
179         self.plugins = pi.get_plugins()