1 # Copyright (C) 2014 Ipsilon Contributors, see COPYING for license
3 from ipsilon.login.common import LoginFormBase, LoginManagerBase
4 from ipsilon.util.plugin import PluginObject
5 from ipsilon.util.log import Log
6 from ipsilon.util import config as pconfig
7 from ipsilon.info.infoldap import InfoProvider as LDAPInfo
11 class LDAP(LoginFormBase, Log):
13 def __init__(self, site, mgr, page):
14 super(LDAP, self).__init__(site, mgr, page)
17 def _ldap_connect(self):
19 tls = self.lm.tls.lower()
22 tls_req_opt = ldap.OPT_X_TLS_NEVER
24 tls_req_opt = ldap.OPT_X_TLS_DEMAND
26 tls_req_opt = ldap.OPT_X_TLS_ALLOW
28 tls_req_opt = ldap.OPT_X_TLS_TRY
29 if tls_req_opt is not None:
30 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)
32 conn = ldap.initialize(self.lm.server_url)
35 if not self.lm.server_url.startswith("ldaps"):
39 def _authenticate(self, username, password):
41 conn = self._ldap_connect()
42 dn = self.lm.bind_dn_tmpl % {'username': username}
43 conn.simple_bind_s(dn, password)
45 # Bypass info plugins to optimize data retrieval
46 if self.lm.get_user_info:
49 if not self.ldap_info:
50 self.ldap_info = LDAPInfo(self._site)
52 return self.ldap_info.get_user_data_from_conn(conn, dn)
56 def POST(self, *args, **kwargs):
57 username = kwargs.get("login_name")
58 password = kwargs.get("login_password")
63 if username and password:
65 userdata = self._authenticate(username, password)
68 for d, v in userdata.get('userdata', {}).items():
70 if 'groups' in userdata:
71 userattrs['groups'] = userdata['groups']
72 if 'extras' in userdata:
73 userattrs['extras'] = userdata['extras']
75 except Exception, e: # pylint: disable=broad-except
76 errmsg = "Authentication failed"
77 self.error("Exception raised: [%s]" % repr(e))
79 errmsg = "Username or password is missing"
83 return self.lm.auth_successful(self.trans, username, 'password',
86 context = self.create_tmpl_context(
89 error_password=not password,
90 error_username=not username
92 # pylint: disable=star-args
93 return self._template('login/form.html', **context)
96 class LoginManager(LoginManagerBase):
98 def __init__(self, *args, **kwargs):
99 super(LoginManager, self).__init__(*args, **kwargs)
103 self.ldap_info = None
104 self.service_name = 'ldap'
105 self.description = """
106 Form based login Manager that uses a simple bind LDAP operation to perform
112 'The LDAP server url.',
113 'ldap://example.com'),
116 'Template to turn username into DN.',
117 'uid=%(username)s,ou=People,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')
169 def get_tree(self, site):
170 self.page = LDAP(site, self, 'login/ldap')
174 class Installer(object):
176 def __init__(self, *pargs):
181 def install_args(self, group):
182 group.add_argument('--ldap', choices=['yes', 'no'], default='no',
183 help='Configure PAM authentication')
184 group.add_argument('--ldap-server-url', action='store',
185 help='LDAP Server Url')
186 group.add_argument('--ldap-bind-dn-template', action='store',
187 help='LDAP Bind DN Template')
189 def configure(self, opts):
190 if opts['ldap'] != 'yes':
193 # Add configuration data to database
194 po = PluginObject(*self.pargs)
197 po.wipe_config_values()
200 if 'ldap_server_url' in opts:
201 config['server url'] = opts['ldap_server_url']
202 if 'ldap_bind_dn_template' in opts:
203 config['bind dn template'] = opts['ldap_bind_dn_template']
204 config['tls'] = 'Demand'
205 po.save_plugin_config(config)
207 # Update global config to add login plugin
209 po.save_enabled_state()