1 # Copyright (C) 2014 Ipsilon Project Contributors
3 # See the file named COPYING for the project license
5 from ipsilon.info.common import InfoProviderBase
6 from ipsilon.info.common import InfoProviderInstaller
7 from ipsilon.util.plugin import PluginObject
8 from ipsilon.util.policy import Policy
9 from ipsilon.util import config as pconfig
13 # TODO: fetch mapping from configuration
16 ['commonname', 'fullname'],
19 ['destinationindicator', 'country'],
20 ['postalcode', 'postcode'],
22 ['statetorprovincename', 'state'],
23 ['streetaddress', 'street'],
24 ['telephonenumber', 'phone'],
28 class InfoProvider(InfoProviderBase):
30 def __init__(self, *pargs):
31 super(InfoProvider, self).__init__(*pargs)
32 self.mapper = Policy(ldap_mapping)
34 self.description = """
35 Info plugin that uses LDAP to retrieve user data. """
40 'The LDAP server url.',
41 'ldap://example.com'),
44 'Template to turn username into DN.',
45 'uid=%(username)s,ou=People,dc=example,dc=com'),
48 'What TLS level show be required',
49 ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
53 'DN to bind as, if empty uses anonymous bind.',
54 'uid=ipsilon,ou=People,dc=example,dc=com'),
57 'Password to use for bind operation'),
62 return self.get_config_value('server url')
66 return self.get_config_value('tls')
70 return self.get_config_value('bind dn')
73 def bind_password(self):
74 return self.get_config_value('bind password')
77 def user_dn_tmpl(self):
78 return self.get_config_value('user dn template')
82 tls = self.tls.lower()
85 tls_req_opt = ldap.OPT_X_TLS_NEVER
87 tls_req_opt = ldap.OPT_X_TLS_DEMAND
89 tls_req_opt = ldap.OPT_X_TLS_ALLOW
91 tls_req_opt = ldap.OPT_X_TLS_TRY
92 if tls_req_opt is not None:
93 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)
95 conn = ldap.initialize(self.server_url)
98 if not self.server_url.startswith("ldaps"):
101 conn.simple_bind_s(self.bind_dn, self.bind_password)
105 def _get_user_data(self, conn, dn):
106 result = conn.search_s(dn, ldap.SCOPE_BASE)
107 if result is None or result == []:
108 raise Exception('User object could not be found!')
109 elif len(result) > 1:
110 raise Exception('No unique user object could be found!')
112 for name, value in result[0][1].iteritems():
113 if type(value) is list and len(value) == 1:
118 def _get_user_groups(self, conn, dn, ldapattrs):
119 # TODO: fixme to support RFC2307bis schemas
120 if 'memberuid' in ldapattrs:
121 return ldapattrs['memberuid']
125 def get_user_data_from_conn(self, conn, dn):
128 ldapattrs = self._get_user_data(conn, dn)
129 userattrs, extras = self.mapper.map_attributes(ldapattrs)
130 groups = self._get_user_groups(conn, dn, ldapattrs)
132 reply['_groups'] = groups
133 reply['_extras'] = {'ldap': extras}
134 except Exception, e: # pylint: disable=broad-except
139 def get_user_attrs(self, user):
141 conn = self._ldap_bind()
142 dn = self.user_dn_tmpl % {'username': user}
143 return self.get_user_data_from_conn(conn, dn)
144 except Exception, e: # pylint: disable=broad-except
149 class Installer(InfoProviderInstaller):
151 def __init__(self, *pargs):
152 super(Installer, self).__init__()
156 def install_args(self, group):
157 group.add_argument('--info-ldap', choices=['yes', 'no'], default='no',
158 help='Use LDAP to populate user attrs')
159 group.add_argument('--info-ldap-server-url', action='store',
160 help='LDAP Server Url')
161 group.add_argument('--info-ldap-bind-dn', action='store',
163 group.add_argument('--info-ldap-bind-pwd', action='store',
164 help='LDAP Bind Password')
165 group.add_argument('--info-ldap-user-dn-template', action='store',
166 help='LDAP User DN Template')
168 def configure(self, opts):
169 if opts['info_ldap'] != 'yes':
172 # Add configuration data to database
173 po = PluginObject(*self.pargs)
176 po.wipe_config_values()
178 if 'info_ldap_server_url' in opts:
179 config['server url'] = opts['info_ldap_server_url']
180 elif 'ldap_server_url' in opts:
181 config['server url'] = opts['ldap_server_url']
182 config = {'bind dn': opts['info_ldap_bind_dn']}
183 config = {'bind password': opts['info_ldap_bind_pwd']}
184 config = {'user dn template': opts['info_ldap_user_dn_template']}
185 if 'info_ldap_bind_dn' in opts:
186 config['bind dn'] = opts['info_ldap_bind_dn']
187 if 'info_ldap_bind_pwd' in opts:
188 config['bind password'] = opts['info_ldap_bind_pwd']
189 if 'info_ldap_user_dn_template' in opts:
190 config['user dn template'] = opts['info_ldap_user_dn_template']
191 elif 'ldap_bind_dn_template' in opts:
192 config['user dn template'] = opts['ldap_bind_dn_template']
193 config['tls'] = 'Demand'
194 po.save_plugin_config(config)
196 # Update global config to add info plugin
198 po.save_enabled_state()