1 # Copyright (C) 2014 Ipsilon Contributors, see COPYING for license
3 from ipsilon.login.common import LoginFormBase, LoginManagerBase, \
5 from ipsilon.util.plugin import PluginObject
6 from ipsilon.util.log import Log
7 from ipsilon.util import config as pconfig
8 from ipsilon.info.infoldap import InfoProvider as LDAPInfo
13 class LDAP(LoginFormBase, Log):
15 def __init__(self, site, mgr, page):
16 super(LDAP, self).__init__(site, mgr, page)
19 def _ldap_connect(self):
21 tls = self.lm.tls.lower()
24 tls_req_opt = ldap.OPT_X_TLS_NEVER
26 tls_req_opt = ldap.OPT_X_TLS_DEMAND
28 tls_req_opt = ldap.OPT_X_TLS_ALLOW
30 tls_req_opt = ldap.OPT_X_TLS_TRY
31 if tls_req_opt is not None:
32 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)
34 conn = ldap.initialize(self.lm.server_url)
37 if not self.lm.server_url.startswith("ldaps"):
41 def _authenticate(self, username, password):
43 conn = self._ldap_connect()
44 dn = self.lm.bind_dn_tmpl % {'username': username}
45 conn.simple_bind_s(dn, password)
47 # Bypass info plugins to optimize data retrieval
48 if self.lm.get_user_info:
51 if not self.ldap_info:
52 self.ldap_info = LDAPInfo(self._site)
54 base = self.lm.base_dn
55 return self.ldap_info.get_user_data_from_conn(conn, dn, base,
60 def POST(self, *args, **kwargs):
61 username = kwargs.get("login_name")
62 password = kwargs.get("login_password")
67 if username and password:
69 userattrs = self._authenticate(username, password)
71 except Exception, e: # pylint: disable=broad-except
72 errmsg = "Authentication failed"
73 self.error("Exception raised: [%s]" % repr(e))
75 errmsg = "Username or password is missing"
79 return self.lm.auth_successful(self.trans, username, 'password',
82 context = self.create_tmpl_context(
85 error_password=not password,
86 error_username=not username
88 self.lm.set_auth_error()
89 # pylint: disable=star-args
90 return self._template('login/form.html', **context)
93 class LoginManager(LoginManagerBase):
95 def __init__(self, *args, **kwargs):
96 super(LoginManager, self).__init__(*args, **kwargs)
100 self.ldap_info = None
101 self.service_name = 'ldap'
102 self.description = """
103 Form based login Manager that uses a simple bind LDAP operation to perform
109 'The LDAP server url.',
110 'ldap://example.com'),
113 'Template to turn username into DN.',
114 'uid=%(username)s,ou=People,dc=example,dc=com'),
117 'The base dn to look for users and groups',
118 'dc=example,dc=com'),
121 'Get user info via ldap using user credentials',
125 'What TLS level show be required',
126 ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
130 'Text used to ask for the username at login time.',
134 'Text used to ask for the password at login time.',
138 'Text used to guide the user at login time.',
139 'Provide your Username and Password')
144 return self.get_config_value('help text')
147 def username_text(self):
148 return self.get_config_value('username text')
151 def password_text(self):
152 return self.get_config_value('password text')
155 def server_url(self):
156 return self.get_config_value('server url')
160 return self.get_config_value('tls')
163 def get_user_info(self):
164 return self.get_config_value('get user info')
167 def bind_dn_tmpl(self):
168 return self.get_config_value('bind dn template')
172 return self.get_config_value('base dn')
174 def get_tree(self, site):
175 self.page = LDAP(site, self, 'login/ldap')
179 class Installer(LoginManagerInstaller):
181 def __init__(self, *pargs):
182 super(Installer, self).__init__()
186 def install_args(self, group):
187 group.add_argument('--ldap', choices=['yes', 'no'], default='no',
188 help='Configure LDAP authentication')
189 group.add_argument('--ldap-server-url', action='store',
190 help='LDAP Server Url')
191 group.add_argument('--ldap-bind-dn-template', action='store',
192 help='LDAP Bind DN Template')
193 group.add_argument('--ldap-tls-level', action='store', default=None,
194 help='LDAP TLS level')
195 group.add_argument('--ldap-base-dn', action='store',
198 def configure(self, opts):
199 if opts['ldap'] != 'yes':
202 # Add configuration data to database
203 po = PluginObject(*self.pargs)
206 po.wipe_config_values()
209 if 'ldap_server_url' in opts:
210 config['server url'] = opts['ldap_server_url']
211 if 'ldap_bind_dn_template' in opts:
212 config['bind dn template'] = opts['ldap_bind_dn_template']
213 if 'ldap_tls_level' in opts and opts['ldap_tls_level'] is not None:
214 config['tls'] = opts['ldap_tls_level']
216 config['tls'] = 'Demand'
217 if 'ldap_base_dn' in opts and opts['ldap_base_dn'] is not None:
218 config['base dn'] = opts['ldap_base_dn']
219 po.save_plugin_config(config)
221 # Update global config to add login plugin
223 po.save_enabled_state()
225 # For selinux enabled platforms permit httpd to connect to ldap,
228 subprocess.call(['/usr/sbin/setsebool', '-P',
229 'httpd_can_connect_ldap=on'])
230 except Exception: # pylint: disable=broad-except