3 # Copyright (C) 2014 Ipsilon Contributors, see COPYING for license
5 from ipsilon.login.common import LoginFormBase, LoginManagerBase
6 from ipsilon.util.plugin import PluginObject
7 from ipsilon.util.log import Log
8 from ipsilon.util import config as pconfig
9 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 return self.ldap_info.get_user_data_from_conn(conn, dn)
58 def POST(self, *args, **kwargs):
59 username = kwargs.get("login_name")
60 password = kwargs.get("login_password")
65 if username and password:
67 userdata = self._authenticate(username, password)
70 for d, v in userdata.get('userdata', {}).items():
72 if 'groups' in userdata:
73 userattrs['groups'] = userdata['groups']
74 if 'extras' in userdata:
75 userattrs['extras'] = userdata['extras']
77 except Exception, e: # pylint: disable=broad-except
78 errmsg = "Authentication failed"
79 self.error("Exception raised: [%s]" % repr(e))
81 errmsg = "Username or password is missing"
85 return self.lm.auth_successful(self.trans, username, 'password',
88 context = self.create_tmpl_context(
91 error_password=not password,
92 error_username=not username
94 # pylint: disable=star-args
95 return self._template('login/form.html', **context)
98 class LoginManager(LoginManagerBase):
100 def __init__(self, *args, **kwargs):
101 super(LoginManager, self).__init__(*args, **kwargs)
105 self.ldap_info = None
106 self.service_name = 'ldap'
107 self.description = """
108 Form based login Manager that uses a simple bind LDAP operation to perform
114 'The LDAP server url.',
115 'ldap://example.com'),
118 'Template to turn username into DN.',
119 'uid=%(username)s,ou=People,dc=example,dc=com'),
122 'Get user info via ldap using user credentials',
126 'What TLS level show be required',
127 ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
131 'Text used to ask for the username at login time.',
135 'Text used to ask for the password at login time.',
139 'Text used to guide the user at login time.',
140 'Provide your Username and Password')
145 return self.get_config_value('help text')
148 def username_text(self):
149 return self.get_config_value('username text')
152 def password_text(self):
153 return self.get_config_value('password text')
156 def server_url(self):
157 return self.get_config_value('server url')
161 return self.get_config_value('tls')
164 def get_user_info(self):
165 return self.get_config_value('get user info')
168 def bind_dn_tmpl(self):
169 return self.get_config_value('bind dn template')
171 def get_tree(self, site):
172 self.page = LDAP(site, self, 'login/ldap')
176 class Installer(object):
178 def __init__(self, *pargs):
183 def install_args(self, group):
184 group.add_argument('--ldap', choices=['yes', 'no'], default='no',
185 help='Configure PAM authentication')
186 group.add_argument('--ldap-server-url', action='store',
187 help='LDAP Server Url')
188 group.add_argument('--ldap-bind-dn-template', action='store',
189 help='LDAP Bind DN Template')
191 def configure(self, opts):
192 if opts['ldap'] != 'yes':
195 # Add configuration data to database
196 po = PluginObject(*self.pargs)
199 po.wipe_config_values()
202 if 'ldap_server_url' in opts:
203 config['server url'] = opts['ldap_server_url']
204 if 'ldap_bind_dn_template' in opts:
205 config['bind dn template'] = opts['ldap_bind_dn_template']
206 config['tls'] = 'Demand'
207 po.save_plugin_config(config)
209 # Update global config to add login plugin
211 po.save_enabled_state()