def get_serverpool(cls, urilist, timeout):
        """
        This create the serverpool for the ldap3 connection.
        The URI from the LDAP resolver can contain a comma separated list of
        LDAP servers. These are split and then added to the pool.

        See
        https://github.com/cannatag/ldap3/blob/master/docs/manual/source/servers.rst#server-pool

        :param urilist: The list of LDAP URIs, comma separated
        :type urilist: basestring
        :param timeout: The connection timeout
        :type timeout: float
        :return: Server Pool
        :rtype: LDAP3 Server Pool Instance
        """
        try:
            strategy = ldap3.POOLING_STRATEGY_ROUND_ROBIN
        except AttributeError:
            # This is for ldap3 >= 2.0.7
            strategy = ldap3.ROUND_ROBIN
        server_pool = ldap3.ServerPool(None, strategy, active=SERVERPOOL_ROUNDS,
                                       exhaust=SERVERPOOL_SKIP)
        for uri in urilist.split(","):
            uri = uri.strip()
            host, port, ssl = cls.split_uri(uri)
            server = ldap3.Server(host, port=port,
                                  use_ssl=ssl,
                                  connect_timeout=float(timeout))
            server_pool.add(server)
            log.debug("Added {0!s}, {1!s}, {2!s} to server pool.".format(host, port, ssl))
        return server_pool
Beispiel #2
0
    def init_app(self, app):
        """
        Configures this extension with the given app. This registers an
        ``teardown_appcontext`` call, and attaches this ``LDAP3LoginManager``
        to it as ``app.ldap3_login_manager``.

        Args:
            app (flask.Flask): The flask app to initialise with
        """

        app.ldap3_login_manager = self
        for k, v in _CONFIG_DEFAULTS:
            app.config.setdefault(k, v)

        app.ldap3_login_manager_server_pool = ldap3.ServerPool(
            [],
            ldap3.FIRST,
            active=1,  # Loop through all servers once.
            exhaust=10,  # Remove unreachable servers for 10 seconds.
        )

        if app.config["LDAP_ADD_SERVER"]:
            self.add_server(
                hostname=app.config["LDAP_HOST"],
                port=app.config["LDAP_PORT"],
                use_ssl=app.config["LDAP_USE_SSL"],
                app=app,
            )

        if hasattr(app, "teardown_appcontext"):
            app.teardown_appcontext(self.teardown)
        else:  # pragma: no cover
            app.teardown_request(self.teardown)
Beispiel #3
0
 def op_adconnect(self, opseq, optotal):
     self.stepmsg("Conecting to the AD", opseq, optotal)
     self.substepmsg("connecting to the first available LDAP server")
     try:
         servers = [
             ldap3.Server(host=server, get_info=ldap3.ALL)
             for server in self.cfg.get("adsync", "host").split()
         ]
         random.shuffle(servers)
         server_pool = ldap3.ServerPool(servers,
                                        pool_strategy=ldap3.FIRST,
                                        active=1)
         user = self.cfg.get("adsync", "user")
         password = self.cfg.get("adsync", "password")
         self.lconn = ldap3.Connection(server=server_pool,
                                       user=user,
                                       password=password,
                                       raise_exceptions=True,
                                       auto_bind=ldap3.AUTO_BIND_NO_TLS,
                                       return_empty_attributes=True)
     except configparser.Error:
         self.handle_cfg_exception(sys.exc_info())
     except LDAPException:
         self.handle_ldap_exception(sys.exc_info())
     self.substepmsg("processing root DSE")
     rootDSE_keys = [
         "defaultNamingContext", "configurationNamingContext",
         "domainFunctionality", "serverName", "dnsHostName"
     ]
     rootDSE_values = [
         x[0] if isinstance(x, list) else x for x in map(
             lambda var: self.lconn.server.info.other[var], rootDSE_keys)
     ]
     self.rootDSE = CaseInsensitiveDict(zip(rootDSE_keys, rootDSE_values))
Beispiel #4
0
    def __init__(self):
        # retrieve settings and initialize connection
        ldap_servers = []
        for server in settings.PUCAS_LDAP['SERVERS']:
            ldap_servers.append(
                ldap3.Server(server, get_info=ldap3.ALL, use_ssl=True))
        server_pool = ldap3.ServerPool(ldap_servers,
                                       ldap3.ROUND_ROBIN,
                                       active=True,
                                       exhaust=5)

        # Load username (in DN format) and password, if in settings
        bind_dn = settings.PUCAS_LDAP.get('BIND_DN', None)
        bind_password = settings.PUCAS_LDAP.get('BIND_PASSWORD', None)

        extra_args = {}
        # Use DN and password if set. Otherwise, use anononymous bind.
        if bind_dn and bind_password:
            extra_args.update({'user': bind_dn, 'password': bind_password})

        try:
            self.conn = ldap3.Connection(server_pool,
                                         auto_bind=True,
                                         **extra_args)
        except LDAPException as err:
            logging.error('Error establishing LDAP connection: %s', err)
            # re-raise to be caught elsewhere
            raise
 def create_ldap_server_pool_obj(self, ldap_servers=None):
     """
     Create ldap3 ServerPool Object
     """
     server_pool = ldap3.ServerPool(
         ldap_servers,
         pool_strategy=self.server_pool_strategy.upper(),
         active=self.server_pool_active,
         exhaust=self.server_pool_exhaust)
     return server_pool
Beispiel #6
0
    def ldapConnectionFactory():
        tls = ldap3.Tls(validate=ldap_cert_verification, version=ssl.PROTOCOL_TLSv1, ca_certs_file=ldap_certs_file)
        server = ldap3.ServerPool(None, ldap3.POOLING_STRATEGY_ROUND_ROBIN, active=True, exhaust=True)
        for q in ldap_servers:
            x=ldap3.Server(q, tls=tls)
            server.add(x)

        conn = ldap3.Connection(server, service_account_user, service_account_pass, check_names=True)
        conn.bind()
        return conn
Beispiel #7
0
 def _load_backends(backends):
     if len(backends) > 1:
         return ldap3.ServerPool([
             Ldap._get_ldap_srv(Ldap._load_backend_config(x))
             for x in backends
         ],
                                 ldap3.ROUND_ROBIN,
                                 active=True,
                                 exhaust=False)
     else:
         return Ldap._get_ldap_srv(Ldap._load_backend_config(backends[0]))
Beispiel #8
0
 def __init__(self):
     self.server_pool = ldap3.ServerPool(
         servers=[ldap3.Server(s, use_ssl=AD_USE_TLS) for s in SERVER_LIST],
         pool_strategy=ldap3.POOLING_STRATEGY_FIRST,
         active=True)
     self.connection = ldap3.Connection(
         self.server_pool,
         user=AD_USER,
         password=AD_PASSWD,
         auto_bind=ldap3.AUTO_BIND_NO_TLS
     )  # use_ssl=True above makes it use TLS, so we don't have to use the StartTLS command in the connection.
     self.connection.raise_exceptions = True
Beispiel #9
0
 def get_connection(self, userdn, password):
     server_pool = ldap3.ServerPool(self.server_address,
                                    ldap3.ROUND_ROBIN,
                                    active=True,
                                    exhaust=True)
     auto_bind = (
         self.use_ssl and ldap3.AUTO_BIND_TLS_BEFORE_BIND or ldap3.AUTO_BIND_NO_TLS
     )
     conn = ldap3.Connection(
         server_pool, user=userdn, password=password, auto_bind=auto_bind
     )
     return conn
Beispiel #10
0
    def __init__(self, app=None):

        self._save_user = None
        self.config = dict(_CONFIG_DEFAULTS)
        self._server_pool = ldap3.ServerPool(
            [],
            ldap3.FIRST,
            active=1,  # Loop through all servers once.
            exhaust=10,  # Remove unreachable servers for 10 seconds.
        )

        if app is not None:
            self.init_app(app)
Beispiel #11
0
    def __init__(self, app=None):

        self._save_user = None
        self.config = {}
        self._server_pool = ldap3.ServerPool(
            [],
            ldap3.POOLING_STRATEGY_FIRST,
            active=1,  # Loop through all servers once. 
            exhaust=10,  # Remove unreachable servers for 10 seconds.
        )

        if app is not None:
            self.init_app(app)
Beispiel #12
0
def ldap_conn():
    """
    Return a ldap connection

    Return value can be used as a context manager
    """
    servers = ldap3.ServerPool([
        ldap3.Server('ldap-labs.eqiad.wikimedia.org'),
        ldap3.Server('ldap-labs.codfw.wikimedia.org'),
    ],
                               ldap3.ROUND_ROBIN,
                               active=True,
                               exhaust=True)
    return ldap3.Connection(servers, read_only=True, auto_bind=True)
Beispiel #13
0
    def _get_server(self, get_info: Optional[str] = None) -> ldap3.ServerPool:
        """Constructs ServerPool from configured LDAP URIs

        Args:
            get_info (str, optional): specifies if the server schema and server
            specific info must be read. Defaults to None.

        Returns:
            Servers grouped in a ServerPool
        """
        return ldap3.ServerPool([
            ldap3.Server(uri, get_info=get_info, tls=self._ldap_tls)
            for uri in self.ldap_uris
        ], )
Beispiel #14
0
    def get_serverpool(cls,
                       urilist,
                       timeout,
                       get_info=None,
                       tls_context=None,
                       rounds=SERVERPOOL_ROUNDS,
                       exhaust=SERVERPOOL_SKIP):
        """
        This create the serverpool for the ldap3 connection.
        The URI from the LDAP resolver can contain a comma separated list of
        LDAP servers. These are split and then added to the pool.

        See
        https://github.com/cannatag/ldap3/blob/master/docs/manual/source/servers.rst#server-pool

        :param urilist: The list of LDAP URIs, comma separated
        :type urilist: basestring
        :param timeout: The connection timeout
        :type timeout: float
        :param get_info: The get_info type passed to the ldap3.Sever
            constructor. default: ldap3.SCHEMA, should be ldap3.NONE in case
            of a bind.
        :param tls_context: A ldap3.tls object, which defines if certificate
            verification should be performed
        :param rounds: The number of rounds we should cycle through the server pool
            before giving up
        :param exhaust: The seconds, for how long a non-reachable server should be
            removed from the serverpool
        :return: Server Pool
        :rtype: LDAP3 Server Pool Instance
        """
        get_info = get_info or ldap3.SCHEMA
        server_pool = ldap3.ServerPool(None,
                                       ldap3.ROUND_ROBIN,
                                       active=rounds,
                                       exhaust=exhaust)
        for uri in urilist.split(","):
            uri = uri.strip()
            host, port, ssl = cls.split_uri(uri)
            server = ldap3.Server(host,
                                  port=port,
                                  use_ssl=ssl,
                                  connect_timeout=float(timeout),
                                  get_info=get_info,
                                  tls=tls_context)
            server_pool.add(server)
            log.debug("Added {0!s}, {1!s}, {2!s} to server pool.".format(
                host, port, ssl))
        return server_pool
Beispiel #15
0
def ldap_conn(config):
    """
    Return a ldap connection
    Return value can be used as a context manager
    """
    servers = ldap3.ServerPool(
        [ldap3.Server(host) for host in config['servers']],
        ldap3.POOLING_STRATEGY_ROUND_ROBIN,
        active=True,
        exhaust=True)
    return ldap3.Connection(servers,
                            read_only=True,
                            user=config['user'],
                            auto_bind=True,
                            password=config['password'])
Beispiel #16
0
 def get_server_pool(self, ldap_domain):
     servers = []
     for s in ldap_domain.servers:
         if not s.is_active:
             continue
         kwargs = {"host": s.address}
         if s.port:
             kwargs["port"] = s.port
         if s.use_tls:
             kwargs["use_ssl"] = True
         servers += [ldap3.Server(**kwargs)]
     if not servers:
         self.logger.error("No active servers configured for domain '%s'", ldap_domain.name)
         return None
     pool = ldap3.ServerPool(servers, ldap3.POOLING_STRATEGY_ROUND_ROBIN)
     return pool
Beispiel #17
0
    def connect(self):
        if time.time() - self.connect_time < 1:
            # The reconnection was done by another thread.
            # We must not reinitialize the connection once again.
            return
        if ( len(configuration.ldap_server) == 0
             or configuration.ldap_server[0].endswith('.domain.org')):
            # Fake LDAP server, do not use it
            return

        servers = [
            ldap3.Server(host, configuration.ldap_server_port,
                         use_ssl = configuration.ldap_server_port in (636, 6360)
                     )
            for host in configuration.ldap_server
            ]
        # configuration.ldap_reconnect
        if len(servers) == 1:
            server_pool = servers[0]
        else:
            server_pool = ldap3.ServerPool(servers,
                                           ldap3.POOLING_STRATEGY_ROUND_ROBIN,
                                           active=True, exhaust=600)
        connection = ldap3.Connection(
            server_pool,
            user = configuration.ldap_server_login,
            password = configuration.ldap_server_password,
            authentication = ldap3.AUTH_SIMPLE,
            raise_exceptions = True,
            client_strategy = ldap3.STRATEGY_ASYNC_THREADED,
            pool_size = 3,
            pool_lifetime = 60
        )
        connection.tls = ldap3.Tls()
        connection.tls.validate = ssl.CERT_NONE
        connection.open()
        connection.start_tls()
        connection.bind()
        old_connection = self.connection
        self.connection = connection
        if old_connection and old_connection is not True:
            try:
                old_connection.unbind()
            except:
                pass
        self.connect_time = time.time()
Beispiel #18
0
    def get_tools(self):
        dn = 'ou=servicegroups,{}'.format(self.config['ldap']['basedn'])
        conn = ldap3.Connection(ldap3.ServerPool(
            [ldap3.Server(s) for s in self.config['ldap']['servers']],
            ldap3.POOLING_STRATEGY_ROUND_ROBIN,
            active=True,
            exhaust=True),
                                read_only=True,
                                user=self.config['ldap']['user'],
                                auto_bind=True,
                                password=self.config['ldap']['password'])

        groups = []
        try:
            conn.search(
                dn,
                '(&(objectclass=groupofnames)(cn=tools.*))',
                ldap3.SEARCH_SCOPE_WHOLE_SUBTREE,
                attributes=['cn'],
                time_limit=5,
                paged_size=256,
            )
            for resp in conn.response:
                groups.append(resp['attributes']['cn'][0].split('.')[1])

            cookie = conn.result['controls']['1.2.840.113556.1.4.319'][
                'value']['cookie']
            while cookie:
                conn.search(
                    dn,
                    '(&(objectclass=groupofnames)(cn=tools.*))',
                    ldap3.SEARCH_SCOPE_WHOLE_SUBTREE,
                    attributes=['cn'],
                    time_limit=5,
                    paged_size=256,
                    paged_cookie=cookie,
                )
                cookie = conn.result['controls']['1.2.840.113556.1.4.319'][
                    'value']['cookie']
                for resp in conn.response:
                    groups.append(resp['attributes']['cn'][0].split('.')[1])
        except Exception:
            logger.exception('Exception getting LDAP data for %s', dn)
        return groups
Beispiel #19
0
    def __init__(self, hosts=None):
        """Set up the LDAP connector.

        Args:
            hosts (list of str): Host URIs to connect to.
        """
        if not hosts:
            hosts = self.DEFAULT_HOSTS

        servers = []
        for host in hosts:
            servers.append(ldap3.Server(
                host,
                connect_timeout=10,  # Wait up to 10 seconds
            ))

        # Only try to reach each server once before reporting error
        # (To avoid getting stuck in a loop waiting forever)
        self.server_pool = ldap3.ServerPool(servers, active=1, exhaust=True)
Beispiel #20
0
 def get_server_pool(self, ldap_domain):
     servers = []
     for s in ldap_domain.servers:
         if not s.is_active:
             continue
         kwargs = {"host": s.address, "connect_timeout": s.connect_timeout}
         if s.port:
             kwargs["port"] = s.port
         if s.use_tls:
             kwargs["use_ssl"] = True
         servers += [ldap3.Server(**kwargs)]
     if not servers:
         self.logger.error("No active servers configured for domain '%s'", ldap_domain.name)
         return None
     pool = ldap3.ServerPool(
         servers,
         self.POOLING_STRATEGIES.get(ldap_domain.ha_policy),
         active=ldap_domain.get_pool_active(),
         exhaust=ldap_domain.get_pool_exhaust(),
     )
     return pool
Beispiel #21
0
def get_ldap_conn(config):
    """
    Return a ldap connection

    Return value can be used as a context manager
    """
    servers = ldap3.ServerPool(
        [
            ldap3.Server(host, connect_timeout=1)
            for host in config["ldap"]["hosts"]
        ],
        ldap3.POOLING_STRATEGY_ROUND_ROBIN,
        active=True,
        exhaust=True,
    )

    return ldap3.Connection(
        servers,
        read_only=True,
        user=config["ldap"]["username"],
        auto_bind=True,
        password=config["ldap"]["password"],
    )
Beispiel #22
0
    def get_serverpool(cls, urilist, timeout, get_info=None):
        """
        This create the serverpool for the ldap3 connection.
        The URI from the LDAP resolver can contain a comma separated list of
        LDAP servers. These are split and then added to the pool.

        See
        https://github.com/cannatag/ldap3/blob/master/docs/manual/source/servers.rst#server-pool

        :param urilist: The list of LDAP URIs, comma separated
        :type urilist: basestring
        :param timeout: The connection timeout
        :type timeout: float
        :param get_info: The get_info type passed to the ldap3.Sever
            constructor. default: ldap3.SCHEMA, should be ldap3.NONE in case
            of a bind.
        :return: Server Pool
        :rtype: LDAP3 Server Pool Instance
        """
        get_info = get_info or ldap3.SCHEMA
        server_pool = ldap3.ServerPool(None,
                                       ldap3.ROUND_ROBIN,
                                       active=SERVERPOOL_ROUNDS,
                                       exhaust=SERVERPOOL_SKIP)
        for uri in urilist.split(","):
            uri = uri.strip()
            host, port, ssl = cls.split_uri(uri)
            server = ldap3.Server(host,
                                  port=port,
                                  use_ssl=ssl,
                                  connect_timeout=float(timeout),
                                  get_info=get_info)
            server_pool.add(server)
            log.debug("Added {0!s}, {1!s}, {2!s} to server pool.".format(
                host, port, ssl))
        return server_pool
Beispiel #23
0
 def __init__(self, ldap_config):
     self.ldap_config = ldap_config
     # Setup a few other config items
     self.page_size = self.ldap_config.get('page_size', 500)
     self.bind_user = self.ldap_config.get('bind_user', None)
     self.bind_password = self.ldap_config.get('bind_password', None)
     pooling_strategy = self.ldap_config.get('pooling_strategy',
                                             'ROUND_ROBIN')
     if pooling_strategy not in ldap3.POOLING_STRATEGIES:
         raise ImproperlyConfigured(
             'LDAP_CONFIG.pooling_strategy must be one of {}'.format(
                 ldap3.POOLING_STRATEGIES))
     self.server_pool = ldap3.ServerPool(None, pooling_strategy)
     logger.debug(
         'Created new LDAP Server Pool with pooling strategy: {}'.format(
             pooling_strategy))
     try:
         server_defns = self.ldap_config.get('servers')
     except AttributeError:
         raise ImproperlyConfigured(
             'ldap_config.servers must be defined and must contain at least one server'
         )
     for server_defn in server_defns:
         self.server_pool.add(self._defn_to_server(server_defn))
Beispiel #24
0
def main():
    logging.basicConfig(level=logging.INFO, stream=sys.stdout)
    parser = argparse.ArgumentParser(
        description=("The Wheel of Misfortune will kill random user "
                     "processes, weighted by age"))
    parser.add_argument(
        "--age",
        "-a",
        type=int,
        default=3,
        help="Age of candidate processes in days, defaults to 3",
    )
    parser.add_argument(
        "--victims",
        "-v",
        type=int,
        default=2,
        help="Number of processes to kill",
    )
    parser.add_argument(
        "--project",
        type=str,
        required=True,
        help="The Cloud VPS project you are running in or simulating",
    )
    parser.add_argument(
        "--min-uid",
        "-m",
        type=int,
        default=500,
        help="Minimum UID to consider kill-worthy",
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Change nothing, just talk about it",
    )
    args = parser.parse_args()

    days = float(args.age * 86400)
    victims = spin_the_wheel(min_uid=args.min_uid,
                             victims=args.victims,
                             age=days)
    if args.dry_run:
        logging.info("I would kill:")
        for vic in victims:
            logging.info(
                vic.as_dict(attrs=["pid", "username", "uids", "name"]))

        sys.exit()

    with open("/etc/ldap.yaml") as f:
        ldap_config = yaml.safe_load(f)
    servers = ldap3.ServerPool(
        [ldap3.Server(s, connect_timeout=1) for s in ldap_config["servers"]],
        ldap3.ROUND_ROBIN,
        active=True,
        exhaust=True,
    )
    with ldap3.Connection(
            servers,
            read_only=True,
            user=ldap_config["user"],
            auto_bind=True,
            password=ldap_config["password"],
            raise_exceptions=True,
            receive_timeout=60,
    ) as conn:
        slay(victims, conn, args.project)
        sys.exit()
Beispiel #25
0
def connection(**kwargs):
    """
    Creates and returns a connection to the LDAP server.

    The user identifier, if given, should be keyword arguments matching the fields
    in settings.LDAP_AUTH_USER_LOOKUP_FIELDS, plus a `password` argument.
    """
    # Format the DN for the username.
    format_username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)
    kwargs = {key: value for key, value in kwargs.items() if value}
    username = None
    password = None
    if kwargs:
        password = kwargs.pop("password")
        username = format_username(kwargs)
    # Configure the connection.
    if settings.LDAP_AUTH_USE_TLS:
        auto_bind = ldap3.AUTO_BIND_TLS_BEFORE_BIND
    else:
        auto_bind = ldap3.AUTO_BIND_NO_TLS
    # Connect.
    try:
        if isinstance(settings.LDAP_AUTH_URL, list):
            server_pool = ldap3.ServerPool()
            for server in settings.LDAP_AUTH_URL:
                server_pool.add(
                    ldap3.Server(
                        server,
                        allowed_referral_hosts=[("*", True)],
                        get_info=ldap3.NONE,
                    ))
        else:
            server_pool = ldap3.Server(
                settings.LDAP_AUTH_URL,
                allowed_referral_hosts=[("*", True)],
                get_info=ldap3.NONE,
            )

        c = ldap3.Connection(
            server_pool,
            user=username,
            password=password,
            auto_bind=auto_bind,
            raise_exceptions=True,
        )
    except LDAPException as ex:
        logger.warning("LDAP connect failed: {ex}".format(ex=ex))
        yield None
        return
    # If the settings specify an alternative username and password for querying, rebind as that.
    if ((settings.LDAP_AUTH_CONNECTION_USERNAME
         or settings.LDAP_AUTH_CONNECTION_PASSWORD)
            and (settings.LDAP_AUTH_CONNECTION_USERNAME != username
                 or settings.LDAP_AUTH_CONNECTION_PASSWORD != password)):
        User = get_user_model()
        try:
            c.rebind(
                user=format_username({
                    User.USERNAME_FIELD:
                    settings.LDAP_AUTH_CONNECTION_USERNAME
                }),
                password=settings.LDAP_AUTH_CONNECTION_PASSWORD,
            )
        except LDAPException as ex:
            logger.warning("LDAP rebind failed: {ex}".format(ex=ex))
            yield None
            return
    # Return the connection.
    logger.info("LDAP connect succeeded")
    try:
        yield Connection(c)
    finally:
        c.unbind()
Beispiel #26
0
    def is_authenticated(self, user, password):
        """Check if ``user``/``password`` couple is valid."""
        servers = self.configuration.get("auth", "ldap_url")
        if ' ' in servers:  # Handle for multiple LDAP server defined in ldap_url with space separation
            servers = servers.split(' ')
            self.logger.debug("Multiple servers: %s" % servers)
            SERVER = ldap3.ServerPool(None)
            for s in servers:
                SERVER.add(ldap3.Server(s))
        else:  # only one server is defined
            self.logger.debug("Single server: %s" % servers)
            SERVER = ldap3.Server(servers)
        BASE = self.configuration.get("auth", "ldap_base")
        ATTRIBUTE = self.configuration.get("auth", "ldap_attribute")
        FILTER = self.configuration.get("auth", "ldap_filter")
        BINDDN = self.configuration.get("auth", "ldap_binddn")
        PASSWORD = self.configuration.get("auth", "ldap_password")
        SCOPE = self.configuration.get("auth", "ldap_scope")
        SUPPORT_EXTENDED = self.configuration.getboolean(
            "auth", "ldap_support_extended", fallback=True)

        if BINDDN and PASSWORD:
            conn = ldap3.Connection(SERVER, BINDDN, PASSWORD)
        else:
            conn = ldap3.Connection(SERVER)
        conn.bind()

        try:
            self.logger.debug("LDAP whoami: %s" %
                              conn.extend.standard.who_am_i())
        except Exception as err:
            self.logger.debug("LDAP error: %s" % err)

        distinguished_name = "%s=%s" % (
            ATTRIBUTE, ldap3imports.escape_attribute_value(user))
        self.logger.debug("LDAP bind for %s in base %s" %
                          (distinguished_name, BASE))

        if FILTER:
            filter_string = "(&(%s)%s)" % (distinguished_name, FILTER)
        else:
            filter_string = distinguished_name
        self.logger.debug("LDAP filter: %s" % filter_string)

        conn.search(search_base=BASE,
                    search_scope=SCOPE,
                    search_filter=filter_string,
                    attributes=[ATTRIBUTE])

        users = conn.response

        if users:
            user_dn = users[0]['dn']
            uid = users[0]['attributes'][ATTRIBUTE]
            self.logger.debug("LDAP user %s (%s) found" % (uid, user_dn))
            try:
                conn = ldap3.Connection(SERVER, user_dn, password)
                conn.bind()
                self.logger.debug(conn.result)
                if SUPPORT_EXTENDED:
                    whoami = conn.extend.standard.who_am_i()
                    self.logger.debug("LDAP whoami: %s" % whoami)
                else:
                    self.logger.debug("LDAP skip extended: call whoami")
                    whoami = conn.result['result'] == 0
                if whoami:
                    self.logger.debug("LDAP bind OK")
                    return True
                else:
                    self.logger.debug("LDAP bind failed")
                    return False
            except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
                self.logger.debug("LDAP invalid credentials")
            except Exception as err:
                self.logger.debug("LDAP error %s" % err)
            return False
        else:
            self.logger.debug("LDAP user %s not found" % user)
            return False
Beispiel #27
0
    async def check_auth(self, username, login_type, login_dict):
        """ Attempt to authenticate a user against an LDAP Server
            and register an account if none exists.

            Returns:
                Canonical user ID if authentication against LDAP was successful
        """
        password = login_dict['password']
        # According to section 5.1.2. of RFC 4513 an attempt to log in with
        # non-empty DN and empty password is called Unauthenticated
        # Authentication Mechanism of Simple Bind which is used to establish
        # an anonymous authorization state and not suitable for user
        # authentication.
        if not password:
            return False

        if username.startswith("@") and ":" in username:
            # username is of the form @foo:bar.com
            username = username.split(":", 1)[0][1:]

        # Used in LDAP queries as value of ldap_attributes['uid'] attribute.
        uid_value = username
        # Default display name for the user, if a new account is registered.
        default_display_name = username
        # Local part of Matrix ID which will be used in registration process
        localpart = username

        if self.ldap_active_directory:
            try:
                (login, domain, localpart) = self._map_login_to_upn(username)
                uid_value = login + "@" + domain
                default_display_name = login
            except ActiveDirectoryUPNException:
                return False

        try:
            tls = ldap3.Tls(validate=ssl.CERT_REQUIRED)
            server = ldap3.ServerPool([
                ldap3.Server(uri, get_info=None, tls=tls)
                for uri in self.ldap_uris
            ], )
            logger.debug("Attempting LDAP connection with %s", self.ldap_uris)

            if self.ldap_mode == LDAPMode.SIMPLE:
                bind_dn = "{prop}={value},{base}".format(
                    prop=self.ldap_attributes['uid'],
                    value=uid_value,
                    base=self.ldap_base)
                result, conn = await self._ldap_simple_bind(server=server,
                                                            bind_dn=bind_dn,
                                                            password=password)
                logger.debug(
                    'LDAP authentication method simple bind returned: '
                    '%s (conn: %s)', result, conn)
                if not result:
                    return False
            elif self.ldap_mode == LDAPMode.SEARCH:
                filters = [(self.ldap_attributes["uid"], uid_value)]
                result, conn, _ = await self._ldap_authenticated_search(
                    server=server, password=password, filters=filters)
                logger.debug(
                    'LDAP auth method authenticated search returned: '
                    '%s (conn: %s)', result, conn)
                if not result:
                    return False
            else:  # pragma: no cover
                raise RuntimeError(
                    'Invalid LDAP mode specified: {mode}'.format(
                        mode=self.ldap_mode))

            try:
                logger.info("User authenticated against LDAP server: %s", conn)
            except NameError:  # pragma: no cover
                logger.warning(
                    "Authentication method yielded no LDAP connection, "
                    "aborting!")
                return False

            # Get full user id from localpart
            user_id = self.account_handler.get_qualified_user_id(localpart)

            # check if user with user_id exists
            if await self.account_handler.check_user_exists(user_id):
                # exists, authentication complete
                if hasattr(conn, "unbind"):
                    await threads.deferToThread(conn.unbind)
                return user_id

            else:
                # does not exist, register
                if self.ldap_mode == LDAPMode.SEARCH:
                    # search enabled, fetch metadata for account creation from
                    # existing ldap connection
                    filters = [(self.ldap_attributes['uid'], uid_value)]

                    result, conn, response = await self._ldap_authenticated_search(
                        server=server,
                        password=password,
                        filters=filters,
                    )

                    # These results will always return an array
                    display_name = response["attributes"].get(
                        self.ldap_attributes["name"], [localpart])
                    display_name = (display_name[0] if len(display_name) == 1
                                    else default_display_name)

                    mail = response["attributes"].get("mail", [None])
                    mail = mail[0] if len(mail) == 1 else None
                else:
                    # search disabled, register account with basic information
                    display_name = default_display_name
                    mail = None

                # Register the user
                user_id = await self.register_user(localpart, display_name,
                                                   mail)

                return user_id

            return False

        except ldap3.core.exceptions.LDAPException as e:
            logger.warning("Error during ldap authentication: %s", e)
            return False
Beispiel #28
0
    async def check_3pid_auth(self, medium, address, password):
        """ Handle authentication against thirdparty login types, such as email

            Args:
                medium (str): Medium of the 3PID (e.g email, msisdn).
                address (str): Address of the 3PID (e.g [email protected] for email).
                password (str): The provided password of the user.

            Returns:
                user_id (str|None): ID of the user if authentication
                    successful. None otherwise.
        """
        if self.ldap_mode != LDAPMode.SEARCH:
            logger.debug(
                "3PID LDAP login/register attempted but LDAP search mode "
                "not enabled. Bailing.")
            return None

        # We currently only support email
        if medium != "email":
            return None

        # Talk to LDAP and check if this email/password combo is correct
        try:
            server = ldap3.ServerPool(
                [ldap3.Server(uri, get_info=None) for uri in self.ldap_uris], )
            logger.debug("Attempting LDAP connection with %s", self.ldap_uris)

            search_filter = [(self.ldap_attributes["mail"], address)]
            result, conn, response = await self._ldap_authenticated_search(
                server=server,
                password=password,
                filters=search_filter,
            )

            logger.debug(
                'LDAP auth method authenticated search returned: '
                '%s (conn: %s) (response: %s)', result, conn, response)

            # Close connection
            if hasattr(conn, "unbind"):
                await threads.deferToThread(conn.unbind)

            if not result:
                return None

            # Extract the username from the search response from the LDAP server
            localpart = response["attributes"].get(self.ldap_attributes["uid"],
                                                   [None])
            localpart = localpart[0] if len(localpart) == 1 else None
            if self.ldap_active_directory and localpart and "@" in localpart:
                (login, domain) = localpart.lower().rsplit("@", 1)
                localpart = login + "/" + domain

                if (self.ldap_default_domain and domain.lower()
                        == self.ldap_default_domain.lower()):
                    # Users in default AD domain don't have `/domain` suffix
                    localpart = login

            givenName = response["attributes"].get(
                self.ldap_attributes["name"], [localpart])
            givenName = givenName[0] if len(givenName) == 1 else localpart

            # Register the user
            user_id = await self.register_user(localpart, givenName, address)

            return user_id

        except ldap3.core.exceptions.LDAPException as e:
            logger.warning("Error during ldap authentication: %s", e)
            raise
Beispiel #29
0
from django.conf import settings
import ldap3

default_app_config = 'wpi_ldap_aux.apps.WPILDAPAuxConfig'

authdn, password = settings.WPI_LDAP_AUX_AUTH
server_pool = ldap3.ServerPool(('ldaps://ldapv2back.wpi.edu', 'ldaps://vmldapalt.wpi.edu', 'ldaps://ldapv2.wpi.edu'),
                               pool_strategy=ldap3.FIRST, active=True, exhaust=True)

def populate_from_ldap(user):
    with ldap3.Connection(server_pool, user=authdn, password=password, client_strategy=ldap3.SYNC, read_only=True,
                          raise_exceptions=True) as conn:
        conn.search(search_base='ou=People,dc=wpi,dc=edu', search_filter='(uid={})'.format(user.username),
                    search_scope=ldap3.LEVEL, attributes=('givenName', 'sn', 'mail'), size_limit=1)
        resp, = conn.response
    attrs = resp['attributes']
    user.first_name, = attrs['givenName']
    user.last_name, = attrs['sn']
    email, = attrs['mail']
    local_part, _, domain = email.rpartition('@')
    user.email = '{}@{}'.format(local_part, domain.lower())
    user.save(update_fields=('first_name', 'last_name', 'email'))
Beispiel #30
0
logger.info('Initialize py-fortress ldap...')
logger.info('ldap host: ' + _ldap_host + ', port:' + str(_ldap_port))

# Map from config string literals to ldap3 logger constants to set logger level:
if _ldap3_log_level_str == 'OFF':
    _ldap3_log_level = OFF
elif _ldap3_log_level_str == 'ERROR':
    _ldap3_log_level = ERROR
elif _ldap3_log_level_str == 'BASIC':
    _ldap3_log_level = BASIC
elif _ldap3_log_level_str == 'PROTOCOL':
    _ldap3_log_level = PROTOCOL
elif _ldap3_log_level_str == 'NETWORK':
    _ldap3_log_level = NETWORK
elif _ldap3_log_level_str == 'EXTENDED':
    _ldap3_log_level = EXTENDED
set_library_log_detail_level(_ldap3_log_level)

# Needed for server/connection pooling:
_srv1 = ldap3.Server(host=_ldap_host,
                     port=_ldap_port,
                     connect_timeout=_ldap_timeout,
                     use_ssl=_ldap_use_ssl)
_srv_pool = ldap3.ServerPool([_srv1],
                             ldap3.ROUND_ROBIN,
                             exhaust=True,
                             active=True)
_usr_pool = ldap3.ServerPool([_srv1],
                             ldap3.ROUND_ROBIN,
                             exhaust=True,
                             active=True)