3 # Copyright (C) 2014 Simo Sorce <simo@redhat.com>
5 # see file 'COPYING' for use and warranty information
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.
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.
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/>.
20 from ipsilon.login.common import LoginPageBase, LoginManagerBase
21 from ipsilon.login.common import FACILITY
22 from ipsilon.util.plugin import PluginObject
23 from ipsilon.util.trans import Transaction
24 from ipsilon.util.user import UserSession
25 from string import Template
30 class Krb(LoginPageBase):
32 def root(self, *args, **kwargs):
33 # Someone typed manually or a robot is walking th tree.
34 # Redirect to default page
35 return self.lm.redirect_to_path(self.lm.path)
38 class KrbAuth(LoginPageBase):
40 def root(self, *args, **kwargs):
41 trans = Transaction('login', **kwargs)
42 # If we can get here, we must be authenticated and remote_user
43 # was set. Check the session has a user set already or error.
46 self.user = us.get_user()
47 if not self.user.is_anonymous:
48 userdata = {'krb_principal_name': self.user.name}
49 return self.lm.auth_successful(trans, self.user.name,
52 return self.lm.auth_failed(trans)
55 class KrbError(LoginPageBase):
57 def root(self, *args, **kwargs):
58 cherrypy.log.error('REQUEST: %s' % cherrypy.request.headers)
59 # If we have no negotiate header return whatever mod_auth_kerb
60 # generated and wait for the next request
62 if 'WWW-Authenticate' not in cherrypy.request.headers:
63 cherrypy.response.status = 401
65 if self.lm.next_login:
66 return self.lm.next_login.page.root(*args, **kwargs)
68 conturl = '%s/login' % self.basepath
69 return self._template('login/krb.html',
70 title='Kerberos Login',
73 # If we get here, negotiate failed
74 return self.lm.auth_failed(Transaction('login', **kwargs))
77 class LoginManager(LoginManagerBase):
79 def __init__(self, *args, **kwargs):
80 super(LoginManager, self).__init__(*args, **kwargs)
82 self.path = 'krb/negotiate'
84 self.description = """
85 Kereros Negotiate authentication plugin. Relies on the mod_auth_kerb apache
86 plugin for actual authentication. """
88 def get_tree(self, site):
89 self.page = Krb(site, self)
90 self.page.__dict__['negotiate'] = KrbAuth(site, self)
91 self.page.__dict__['unauthorized'] = KrbError(site, self)
92 self.page.__dict__['failed'] = KrbError(site, self)
98 <Location /${instance}/login/krb/negotiate>
100 AuthName "Kerberos Login"
101 KrbMethodNegotiate on
102 KrbMethodK5Passwd off
106 KrbSaveCredentials off
107 KrbConstrainedDelegation off
108 # KrbLocalUserMapping On
111 ErrorDocument 401 /${instance}/login/krb/unauthorized
112 ErrorDocument 500 /${instance}/login/krb/failed
117 class Installer(object):
123 def install_args(self, group):
124 group.add_argument('--krb', choices=['yes', 'no'], default='no',
125 help='Configure Kerberos authentication')
126 group.add_argument('--krb-realms',
127 help='Allowed Kerberos Auth Realms')
128 group.add_argument('--krb-httpd-keytab',
129 default='/etc/httpd/conf/http.keytab',
130 help='Kerberos keytab location for HTTPD')
132 def configure(self, opts):
133 if opts['krb'] != 'yes':
136 confopts = {'instance': opts['instance']}
138 if os.path.exists(opts['krb_httpd_keytab']):
139 confopts['keytab'] = ' Krb5KeyTab %s' % opts['krb_httpd_keytab']
141 raise Exception('Keytab not found')
143 if opts['krb_realms'] is None:
144 confopts['realms'] = ' # KrbAuthRealms - Any realm is allowed'
146 confopts['realms'] = ' KrbAuthRealms %s' % opts['krb_realms']
148 tmpl = Template(CONF_TEMPLATE)
149 hunk = tmpl.substitute(**confopts) # pylint: disable=star-args
150 with open(opts['httpd_conf'], 'a') as httpd_conf:
151 httpd_conf.write(hunk)
153 # Add configuration data to database
158 # Update global config, put 'krb' always first
160 globalconf = po.get_plugin_config(FACILITY)
161 if 'order' in globalconf:
162 order = globalconf['order'].split(',')
165 order.insert(0, 'krb')
166 globalconf['order'] = ','.join(order)
167 po.set_config(globalconf)
168 po.save_plugin_config(FACILITY)