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
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)
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))
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
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
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]))
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
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
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)
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)
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)
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 ], )
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
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'])
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
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()
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
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)
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
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"], )
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
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))
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()
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()
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
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
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
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'))
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)