-#!/usr/bin/python
-#
# Copyright (C) 2014 Ipsilon Project Contributors
#
# See the file named COPYING for the project license
from ipsilon.info.common import InfoProviderBase
from ipsilon.info.common import InfoProviderInstaller
+from ipsilon.info.common import InfoMapping
from ipsilon.util.plugin import PluginObject
-from ipsilon.util.log import Log
+from ipsilon.util import config as pconfig
import ldap
-class InfoProvider(InfoProviderBase, Log):
+# TODO: fetch mapping from configuration
+ldap_mapping = {
+ 'cn': 'fullname',
+ 'commonname': 'fullname',
+ 'sn': 'surname',
+ 'mail': 'email',
+ 'destinationindicator': 'country',
+ 'postalcode': 'postcode',
+ 'st': 'state',
+ 'statetorprovincename': 'state',
+ 'streetaddress': 'street',
+ 'telephonenumber': 'phone',
+}
+
- def __init__(self):
- super(InfoProvider, self).__init__()
+class InfoProvider(InfoProviderBase):
+
+ def __init__(self, *pargs):
+ super(InfoProvider, self).__init__(*pargs)
+ self.mapper = InfoMapping()
+ self.mapper.set_mapping(ldap_mapping)
self.name = 'ldap'
self.description = """
Info plugin that uses LDAP to retrieve user data. """
- self._options = {
- 'server url': [
- """ The LDAP server url """,
- 'string',
- 'ldap://example.com'
- ],
- 'tls': [
- " What TLS level show be required " +
- "(Demand, Allow, Try, Never, NoTLS) ",
- 'string',
- 'Demand'
- ],
- 'bind dn': [
- """ User DN to bind as, if empty uses anonymous bind. """,
- 'string',
- 'uid=ipsilon,ou=People,dc=example,dc=com'
- ],
- 'bind password': [
- """ Password to use for bind operation """,
- 'string',
- 'Password'
- ],
- 'user dn template': [
- """ Template to turn username into DN. """,
- 'string',
- 'uid=%(username)s,ou=People,dc=example,dc=com'
- ],
- }
+ self.new_config(
+ self.name,
+ pconfig.String(
+ 'server url',
+ 'The LDAP server url.',
+ 'ldap://example.com'),
+ pconfig.Template(
+ 'user dn template',
+ 'Template to turn username into DN.',
+ 'uid=%(username)s,ou=People,dc=example,dc=com'),
+ pconfig.Pick(
+ 'tls',
+ 'What TLS level show be required',
+ ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
+ 'Demand'),
+ pconfig.String(
+ 'bind dn',
+ 'DN to bind as, if empty uses anonymous bind.',
+ 'uid=ipsilon,ou=People,dc=example,dc=com'),
+ pconfig.String(
+ 'bind password',
+ 'Password to use for bind operation'),
+ )
@property
def server_url(self):
return conn
- def get_user_data_from_conn(self, conn, dn):
+ def _get_user_data(self, conn, dn):
result = conn.search_s(dn, ldap.SCOPE_BASE)
if result is None or result == []:
raise Exception('User object could not be found!')
elif len(result) > 1:
raise Exception('No unique user object could be found!')
- return result[0][1]
+ data = dict()
+ for name, value in result[0][1].iteritems():
+ if type(value) is list and len(value) == 1:
+ value = value[0]
+ data[name] = value
+ return data
+
+ def _get_user_groups(self, conn, dn, ldapattrs):
+ # TODO: fixme to support RFC2307bis schemas
+ if 'memberuid' in ldapattrs:
+ return ldapattrs['memberuid']
+ else:
+ return []
+
+ def get_user_data_from_conn(self, conn, dn):
+ reply = dict()
+ try:
+ ldapattrs = self._get_user_data(conn, dn)
+ userattrs, extras = self.mapper.map_attrs(ldapattrs)
+ groups = self._get_user_groups(conn, dn, ldapattrs)
+ reply['userdata'] = userattrs
+ reply['groups'] = groups
+ reply['extras'] = {'ldap': extras}
+ except Exception, e: # pylint: disable=broad-except
+ self.error(e)
+
+ return reply
def get_user_attrs(self, user):
- userattrs = None
try:
conn = self._ldap_bind()
dn = self.user_dn_tmpl % {'username': user}
- userattrs = self.get_user_data_from_conn(conn, dn)
+ return self.get_user_data_from_conn(conn, dn)
except Exception, e: # pylint: disable=broad-except
self.error(e)
-
- return userattrs
+ return {}
class Installer(InfoProviderInstaller):
- def __init__(self):
+ def __init__(self, *pargs):
super(Installer, self).__init__()
- self.name = 'nss'
+ self.name = 'ldap'
+ self.pargs = pargs
def install_args(self, group):
group.add_argument('--info-ldap', choices=['yes', 'no'], default='no',
return
# Add configuration data to database
- po = PluginObject()
+ po = PluginObject(*self.pargs)
po.name = 'ldap'
po.wipe_data()
- po.wipe_config_values(self.facility)
+ po.wipe_config_values()
config = dict()
if 'info_ldap_server_url' in opts:
config['server url'] = opts['info_ldap_server_url']
elif 'ldap_bind_dn_template' in opts:
config['user dn template'] = opts['ldap_bind_dn_template']
config['tls'] = 'Demand'
- po.set_config(config)
- po.save_plugin_config(self.facility)
-
- # Replace global config, only one plugin info can be used
- po.name = 'global'
- globalconf = po.get_plugin_config(self.facility)
- if 'order' in globalconf:
- order = globalconf['order'].split(',')
- else:
- order = []
- order.append('ldap')
- globalconf['order'] = ','.join(order)
- po.set_config(globalconf)
- po.save_plugin_config(self.facility)
+ po.save_plugin_config(config)
+
+ # Update global config to add login plugin
+ po.is_enabled = True
+ po.save_enabled_state()