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
12 class LDAP(LoginFormBase, Log):
14 def __init__(self, site, mgr, page):
15 super(LDAP, self).__init__(site, mgr, page)
18 def _ldap_connect(self):
20 tls = self.lm.tls.lower()
23 tls_req_opt = ldap.OPT_X_TLS_NEVER
25 tls_req_opt = ldap.OPT_X_TLS_DEMAND
27 tls_req_opt = ldap.OPT_X_TLS_ALLOW
29 tls_req_opt = ldap.OPT_X_TLS_TRY
30 if tls_req_opt is not None:
31 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)
33 conn = ldap.initialize(self.lm.server_url)
36 if not self.lm.server_url.startswith("ldaps"):
40 def _authenticate(self, username, password):
42 conn = self._ldap_connect()
43 dn = self.lm.bind_dn_tmpl % {'username': username}
44 conn.simple_bind_s(dn, password)
46 # Bypass info plugins to optimize data retrieval
47 if self.lm.get_user_info:
50 if not self.ldap_info:
51 self.ldap_info = LDAPInfo(self._site)
53 return self.ldap_info.get_user_data_from_conn(conn, dn)
57 def POST(self, *args, **kwargs):
58 username = kwargs.get("login_name")
59 password = kwargs.get("login_password")
64 if username and password:
66 userattrs = self._authenticate(username, password)
68 except Exception, e: # pylint: disable=broad-except
69 errmsg = "Authentication failed"
70 self.error("Exception raised: [%s]" % repr(e))
72 errmsg = "Username or password is missing"
76 return self.lm.auth_successful(self.trans, username, 'password',
79 context = self.create_tmpl_context(
82 error_password=not password,
83 error_username=not username
85 # pylint: disable=star-args
86 return self._template('login/form.html', **context)
89 class LoginManager(LoginManagerBase):
91 def __init__(self, *args, **kwargs):
92 super(LoginManager, self).__init__(*args, **kwargs)
97 self.service_name = 'ldap'
98 self.description = """
99 Form based login Manager that uses a simple bind LDAP operation to perform
105 'The LDAP server url.',
106 'ldap://example.com'),
109 'Template to turn username into DN.',
110 'uid=%(username)s,ou=People,dc=example,dc=com'),
113 'Get user info via ldap using user credentials',
117 'What TLS level show be required',
118 ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
122 'Text used to ask for the username at login time.',
126 'Text used to ask for the password at login time.',
130 'Text used to guide the user at login time.',
131 'Provide your Username and Password')
136 return self.get_config_value('help text')
139 def username_text(self):
140 return self.get_config_value('username text')
143 def password_text(self):
144 return self.get_config_value('password text')
147 def server_url(self):
148 return self.get_config_value('server url')
152 return self.get_config_value('tls')
155 def get_user_info(self):
156 return self.get_config_value('get user info')
159 def bind_dn_tmpl(self):
160 return self.get_config_value('bind dn template')
162 def get_tree(self, site):
163 self.page = LDAP(site, self, 'login/ldap')
167 class Installer(LoginManagerInstaller):
169 def __init__(self, *pargs):
170 super(Installer, self).__init__()
174 def install_args(self, group):
175 group.add_argument('--ldap', choices=['yes', 'no'], default='no',
176 help='Configure LDAP authentication')
177 group.add_argument('--ldap-server-url', action='store',
178 help='LDAP Server Url')
179 group.add_argument('--ldap-bind-dn-template', action='store',
180 help='LDAP Bind DN Template')
182 def configure(self, opts):
183 if opts['ldap'] != 'yes':
186 # Add configuration data to database
187 po = PluginObject(*self.pargs)
190 po.wipe_config_values()
193 if 'ldap_server_url' in opts:
194 config['server url'] = opts['ldap_server_url']
195 if 'ldap_bind_dn_template' in opts:
196 config['bind dn template'] = opts['ldap_bind_dn_template']
197 config['tls'] = 'Demand'
198 po.save_plugin_config(config)
200 # Update global config to add login plugin
202 po.save_enabled_state()