You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.8 KiB
72 lines
2.8 KiB
# coding=utf-8
|
|
#
|
|
# Copyright (C) 2009-2021 Splunk Inc. All Rights Reserved.
|
|
|
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
|
|
from collections import OrderedDict
|
|
|
|
import app
|
|
import ldap3
|
|
from .six import itervalues
|
|
from .six.moves import filter
|
|
|
|
|
|
class ConnectionPool(object):
|
|
"""
|
|
Represents the set of domains defined in ldap.conf as a set of LDAP Connection objects.
|
|
|
|
This class supports domain name selection by the ldapfetch, ldapfilter, and ldapgroup commands. These commands
|
|
:py:meth:`~ConnectionPool.select` a domain to query for each input event record they process. Connections are
|
|
instantiated and opened on first use and closed on :py:meth:`~ConnectionPool.__exit__`.
|
|
|
|
"""
|
|
def __init__(self, configuration, attributes):
|
|
self.configuration = configuration
|
|
self.connections = OrderedDict()
|
|
self.attributes = attributes
|
|
|
|
def __enter__(self):
|
|
self.attributes = app.get_normalized_attribute_names(self.attributes, self.select('default'), self.configuration)
|
|
return self
|
|
|
|
def __exit__(self, exception_type, exception, traceback):
|
|
for connection in filter(None, itervalues(self.connections)):
|
|
try:
|
|
connection.unbind()
|
|
except Exception as error:
|
|
# Socket is sometimes closed before the connection.strategy.close method is called by connection.unbind
|
|
# Further, for reasons yet to be ascertained, the error caught by Python at this site is NOT recognized
|
|
# for what it is: an ldap3.LDAPSocketCloseError. Hence, we catch any exception here and--for now--
|
|
# hope for the best.
|
|
# TODO: Get a fix to this issue when we next update ldap3 or pin it on the Python runtime and let it be
|
|
self.configuration.command.logger.debug('Swallowed exception of type %s: %s', type(error), error)
|
|
pass
|
|
|
|
self.configuration.command.logger.debug('Re-raise exception type: %s', exception_type)
|
|
return exception_type is None # meaning: do not swallow, but re-raise any exception presented by the runtime
|
|
|
|
def select(self, domain):
|
|
|
|
connection = self.connections.get(domain)
|
|
|
|
if connection is None:
|
|
|
|
configuration = self.configuration
|
|
try:
|
|
configuration.select(domain)
|
|
except KeyError:
|
|
self.connections[domain] = connection = None
|
|
else:
|
|
connection = ldap3.Connection(
|
|
configuration.server,
|
|
read_only=True,
|
|
raise_exceptions=True,
|
|
user=configuration.credentials.username,
|
|
password=configuration.credentials.password)
|
|
|
|
connection.bind()
|
|
self.connections[domain] = connection
|
|
|
|
return connection
|