diff options
author | Simo Sorce <simo@redhat.com> | 2014-08-28 14:59:13 -0400 |
---|---|---|
committer | Patrick Uiterwijk <puiterwijk@redhat.com> | 2014-09-24 20:51:53 +0200 |
commit | f8699581dbcf5ba39a93b6202e577260c498b102 (patch) | |
tree | 8acbbb7165a2e35c790ae3cde196fd9fd4906352 /ipsilon/info/infoldap.py | |
parent | 39375ee6ce6b65737670f5a7f850d6f75d328d21 (diff) | |
download | ipsilon-f8699581dbcf5ba39a93b6202e577260c498b102.tar.gz ipsilon-f8699581dbcf5ba39a93b6202e577260c498b102.tar.xz ipsilon-f8699581dbcf5ba39a93b6202e577260c498b102.zip |
Add very simple LDAP authentication plugin
Uses python-ldap to perform a simple bind after connecting to
the LDAP server using (by default) a TLS encrypted connection.
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Patrick Uiterwijk <puiterwijk@redhat.com>
Diffstat (limited to 'ipsilon/info/infoldap.py')
-rwxr-xr-x | ipsilon/info/infoldap.py | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/ipsilon/info/infoldap.py b/ipsilon/info/infoldap.py new file mode 100755 index 0000000..6d710bd --- /dev/null +++ b/ipsilon/info/infoldap.py @@ -0,0 +1,172 @@ +#!/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.util.plugin import PluginObject +from ipsilon.util.log import Log +import ldap + + +class InfoProvider(InfoProviderBase, Log): + + def __init__(self): + super(InfoProvider, self).__init__() + 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' + ], + } + + @property + def server_url(self): + return self.get_config_value('server url') + + @property + def tls(self): + return self.get_config_value('tls') + + @property + def bind_dn(self): + return self.get_config_value('bind dn') + + @property + def bind_password(self): + return self.get_config_value('bind password') + + @property + def user_dn_tmpl(self): + return self.get_config_value('user dn template') + + def _ldap_bind(self): + + tls = self.tls.lower() + tls_req_opt = None + if tls == "never": + tls_req_opt = ldap.OPT_X_TLS_NEVER + elif tls == "demand": + tls_req_opt = ldap.OPT_X_TLS_DEMAND + elif tls == "allow": + tls_req_opt = ldap.OPT_X_TLS_ALLOW + elif tls == "try": + tls_req_opt = ldap.OPT_X_TLS_TRY + if tls_req_opt is not None: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt) + + conn = ldap.initialize(self.server_url) + + if tls != "notls": + if not self.server_url.startswith("ldaps"): + conn.start_tls_s() + + conn.simple_bind_s(self.bind_dn, self.bind_password) + + return conn + + def get_user_data_from_conn(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] + + 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) + except Exception, e: # pylint: disable=broad-except + self.error(e) + + return userattrs + + +class Installer(InfoProviderInstaller): + + def __init__(self): + super(Installer, self).__init__() + self.name = 'nss' + + def install_args(self, group): + group.add_argument('--info-ldap', choices=['yes', 'no'], default='no', + help='Use LDAP to populate user attrs') + group.add_argument('--info-ldap-server-url', action='store', + help='LDAP Server Url') + group.add_argument('--info-ldap-bind-dn', action='store', + help='LDAP Bind DN') + group.add_argument('--info-ldap-bind-pwd', action='store', + help='LDAP Bind Password') + group.add_argument('--info-ldap-user-dn-template', action='store', + help='LDAP User DN Template') + + def configure(self, opts): + if opts['info_ldap'] != 'yes': + return + + # Add configuration data to database + po = PluginObject() + po.name = 'ldap' + po.wipe_data() + po.wipe_config_values(self.facility) + config = dict() + if 'info_ldap_server_url' in opts: + config['server url'] = opts['info_ldap_server_url'] + elif 'ldap_server_url' in opts: + config['server url'] = opts['ldap_server_url'] + config = {'bind dn': opts['info_ldap_bind_dn']} + config = {'bind password': opts['info_ldap_bind_pwd']} + config = {'user dn template': opts['info_ldap_user_dn_template']} + if 'info_ldap_bind_dn' in opts: + config['bind dn'] = opts['info_ldap_bind_dn'] + if 'info_ldap_bind_pwd' in opts: + config['bind password'] = opts['info_ldap_bind_pwd'] + if 'info_ldap_user_dn_template' in opts: + config['user dn template'] = opts['info_ldap_user_dn_template'] + 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) |