3 # Copyright (C) 2014 Ipsilon Contributors, see COPYING for license
5 from ipsilon.login.common import LoginFormBase, LoginManagerBase
6 from ipsilon.login.common import FACILITY
7 from ipsilon.util.plugin import PluginObject
8 from ipsilon.util.log import Log
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()
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
112 """ The text shown to guide the user at login time. """,
114 'Insert your Username and Password and then submit.'
117 """ The text shown to ask for the username in the form. """,
122 """ The text shown to ask for the password in the form. """,
127 """ The LDAP server url """,
132 " What TLS level show be required " +
133 "(Demand, Allow, Try, Never, NoTLS) ",
137 'bind dn template': [
138 """ Template to turn username into DN. """,
140 'uid=%(username)s,ou=People,dc=example,dc=com'
143 """ Get user info via ldap directly after auth (Yes/No) """,
148 self.conf_opt_order = ['server url', 'bind dn template',
149 'get user info', 'tls', 'username text',
150 'password text', 'help text']
154 return self.get_config_value('help text')
157 def username_text(self):
158 return self.get_config_value('username text')
161 def password_text(self):
162 return self.get_config_value('password text')
165 def server_url(self):
166 return self.get_config_value('server url')
170 return self.get_config_value('tls')
173 def get_user_info(self):
174 return (self.get_config_value('get user info').lower() == 'yes')
177 def bind_dn_tmpl(self):
178 return self.get_config_value('bind dn template')
180 def get_tree(self, site):
181 self.page = LDAP(site, self, 'login/ldap')
185 class Installer(object):
191 def install_args(self, group):
192 group.add_argument('--ldap', choices=['yes', 'no'], default='no',
193 help='Configure PAM authentication')
194 group.add_argument('--ldap-server-url', action='store',
195 help='LDAP Server Url')
196 group.add_argument('--ldap-bind-dn-template', action='store',
197 help='LDAP Bind DN Template')
199 def configure(self, opts):
200 if opts['ldap'] != 'yes':
203 # Add configuration data to database
208 po.wipe_config_values(FACILITY)
210 if 'ldap_server_url' in opts:
211 config['server url'] = opts['ldap_server_url']
212 if 'ldap_bind_dn_template' in opts:
213 config['bind dn template'] = opts['ldap_bind_dn_template']
214 config['tls'] = 'Demand'
215 po.save_plugin_config(FACILITY, config)
217 # Update global config to add login plugin
220 globalconf = po.get_plugin_config(FACILITY)
221 if 'order' in globalconf:
222 order = globalconf['order'].split(',')
226 globalconf['order'] = ','.join(order)
227 po.save_plugin_config(FACILITY, globalconf)