1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
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 return self._template('login/form.html', **context)
92 class LoginManager(LoginManagerBase):
94 def __init__(self, *args, **kwargs):
95 super(LoginManager, self).__init__(*args, **kwargs)
100 self.service_name = 'ldap'
101 self.description = """
102 Form based login Manager that uses a simple bind LDAP operation to perform
108 'The LDAP server url.',
109 'ldap://example.com'),
112 'Template to turn username into DN.',
113 'uid=%(username)s,ou=People,dc=example,dc=com'),
116 'The base dn to look for users and groups',
117 'dc=example,dc=com'),
120 'Get user info via ldap using user credentials',
124 'What TLS level show be required',
125 ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
129 'Text used to ask for the username at login time.',
133 'Text used to ask for the password at login time.',
137 'Text used to guide the user at login time.',
138 'Provide your Username and Password')
143 return self.get_config_value('help text')
146 def username_text(self):
147 return self.get_config_value('username text')
150 def password_text(self):
151 return self.get_config_value('password text')
154 def server_url(self):
155 return self.get_config_value('server url')
159 return self.get_config_value('tls')
162 def get_user_info(self):
163 return self.get_config_value('get user info')
166 def bind_dn_tmpl(self):
167 return self.get_config_value('bind dn template')
171 return self.get_config_value('base dn')
173 def get_tree(self, site):
174 self.page = LDAP(site, self, 'login/ldap')
178 class Installer(LoginManagerInstaller):
180 def __init__(self, *pargs):
181 super(Installer, self).__init__()
185 def install_args(self, group):
186 group.add_argument('--ldap', choices=['yes', 'no'], default='no',
187 help='Configure LDAP authentication')
188 group.add_argument('--ldap-server-url', action='store',
189 help='LDAP Server Url')
190 group.add_argument('--ldap-bind-dn-template', action='store',
191 help='LDAP Bind DN Template')
192 group.add_argument('--ldap-tls-level', action='store', default=None,
193 help='LDAP TLS level')
194 group.add_argument('--ldap-base-dn', action='store',
197 def configure(self, opts):
198 if opts['ldap'] != 'yes':
201 # Add configuration data to database
202 po = PluginObject(*self.pargs)
205 po.wipe_config_values()
208 if 'ldap_server_url' in opts:
209 config['server url'] = opts['ldap_server_url']
210 if 'ldap_bind_dn_template' in opts:
211 config['bind dn template'] = opts['ldap_bind_dn_template']
212 if 'ldap_tls_level' in opts and opts['ldap_tls_level'] is not None:
213 config['tls'] = opts['ldap_tls_level']
215 config['tls'] = 'Demand'
216 if 'ldap_base_dn' in opts and opts['ldap_base_dn'] is not None:
217 config['base dn'] = opts['ldap_base_dn']
218 po.save_plugin_config(config)
220 # Update global config to add login plugin
222 po.save_enabled_state()
224 # For selinux enabled platforms permit httpd to connect to ldap,
227 subprocess.call(['/usr/sbin/setsebool', '-P',
228 'httpd_can_connect_ldap=on'])
229 except Exception: # pylint: disable=broad-except