def test_max_lifetime(self): if not LDAP: return dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' pool = ConnectionManager('ldap://localhost', dn, passwd, max_lifetime=0.5, use_pool=True) with pool.connection('bind', 'password') as conn: self.assertTrue(conn.active) self.assertFalse(conn.active) self.assertTrue(conn.connected) # same bind and password: reuse with pool.connection('bind', 'passwd') as conn2: self.assertTrue(conn2.active) self.assertTrue(conn is conn2) time.sleep(0.6) # same bind and password, but max lifetime reached: new one with pool.connection('bind', 'passwd') as conn3: self.assertTrue(conn3.active) self.assertTrue(conn3 is not conn2) self.assertTrue(conn3 is not conn)
def test_pool_reuse(self): if not LDAP: return dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' pool = ConnectionManager('ldap://localhost', dn, passwd, use_pool=True) with pool.connection() as conn: self.assertTrue(conn.active) self.assertFalse(conn.active) self.assertTrue(conn.connected) with pool.connection() as conn2: pass self.assertTrue(conn is conn2) with pool.connection() as conn: conn.connected = False with pool.connection() as conn2: pass self.assertTrue(conn is not conn2) # same bind and password: reuse with pool.connection('bind', 'passwd') as conn: self.assertTrue(conn.active) self.assertFalse(conn.active) self.assertTrue(conn.connected) with pool.connection('bind', 'passwd') as conn2: pass self.assertTrue(conn is conn2) # same bind different password, inactive: rebind with pool.connection('bind', 'passwd') as conn: self.assertTrue(conn.active) self.assertFalse(conn.active) self.assertTrue(conn.connected) with pool.connection('bind', 'passwd2') as conn2: pass self.assertTrue(conn is conn2)
def test_pool_cleanup(self): if not LDAP: return dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' pool = ConnectionManager('ldap://localhost', dn, passwd, size=1, use_pool=True) with pool.connection('bind1') as conn: # NOQA pass with pool.connection('bind2') as conn: # NOQA pass # the second call should have removed the first conn self.assertEqual(len(pool), 1)
def __init__(self, ldapuri, allow_new_users=True, users_root='ou=users,dc=mozilla', check_account_state=True, ldap_timeout=10, search_root='dc=mozilla', **kw): self.allow_new_users = allow_new_users self.check_account_state = check_account_state self.users_root = users_root self.search_root = search_root self.ldap_timeout = ldap_timeout self.logger = CLIENT_HOLDER.default_client kw.pop("check_node", None) self.conn = ConnectionManager(ldapuri, **kw)
def test_simple_bind_fails_proper_msg(self): if not LDAP: return # the binding fails with an LDAPError StateConnector.simple_bind_s = _bind_fails2 uri = '' dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' cm = ConnectionManager(uri, dn, passwd, use_pool=True, size=2) self.assertEqual(len(cm), 0) try: with cm.connection('dn', 'pass'): pass except BackendError, err: wanted = ("BackendError\nLDAP Connector (disconnected)\n\n" "I am down") self.assertEqual(wanted, str(err))
def test_pool_full(self): if not LDAP: return dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' pool = ConnectionManager('ldap://localhost', dn, passwd, size=1, retry_delay=1., retry_max=5, use_pool=True) class Worker(threading.Thread): def __init__(self, pool, duration): threading.Thread.__init__(self) self.pool = pool self.duration = duration def run(self): with self.pool.connection() as conn: # NOQA time.sleep(self.duration) def tryit(): with pool.connection() as conn: # NOQA pass # an attempt on a full pool should eventually work # because the connector is reused for i in range(10): tryit() # we have 1 non-active connector now self.assertEqual(len(pool), 1) # an attempt with a full pool should succeed if a # slot gets freed in less than one second. worker1 = Worker(pool, .4) worker1.start() try: tryit() finally: worker1.join() # an attempt with a full pool should fail # if no slot gets freed in less than one second. worker1 = Worker(pool, 1.1) worker1.start() time.sleep(0.1) try: self.assertRaises(MaxConnectionReachedError, tryit) finally: worker1.join() # we still have one active connector self.assertEqual(len(pool), 1)
def __init__(self, ldapuri, users_root='ou=users,dc=mozilla', check_account_state=True, ldap_timeout=10, search_root='dc=mozilla', **kw): self.check_account_state = check_account_state self.users_root = users_root self.search_root = search_root self.ldap_timeout = ldap_timeout self.conn = ConnectionManager(ldapuri, **kw)
def test_timeout_retry(self): if not LDAP: return # the binding fails with an LDAPError StateConnector.simple_bind_s = _bind_fails3 uri = '' dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' cm = ConnectionManager(uri, dn, passwd, use_pool=True, size=2) self.assertEqual(len(cm), 0) counter = _CALL_COUNTER try: with cm.connection('dn', 'pass'): pass except BackendError, err: wanted = 'BackendTimeoutError\n\nBoo' self.assertEqual(wanted, str(err))
def test_simple_bind_fails(self): if not LDAP: return # the binding fails with an LDAPError StateConnector.simple_bind_s = _bind_fails uri = 'ldap://localhost:2222' dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' cm = ConnectionManager(uri, dn, passwd, use_pool=True, size=2) self.assertEqual(len(cm), 0) wanted = ("LDAP Connector (disconnected) - who: 'dn' - uri: " "'ldap://localhost:2222'") wanted2 = ("BackendError\nLDAP Connector (disconnected) - " "who: 'dn' - uri: 'ldap://localhost:2222'\n\n" "LDAP connection invalid") try: with cm.connection('dn', 'pass'): pass except BackendError, e: self.assertEqual(str(e.backend), wanted) self.assertEqual(str(e), wanted2)
def test_connection(self): if not LDAP: return uri = '' dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' cm = ConnectionManager(uri, dn, passwd, use_pool=True, size=2) self.assertEqual(len(cm), 0) with cm.connection('dn', 'pass'): self.assertEqual(len(cm), 1) # if we ask a new one the pool will grow with cm.connection('dn', 'pass'): self.assertEqual(len(cm), 2) # every connector is marked active self.assertTrue(cm._pool[0].active) self.assertTrue(cm._pool[1].active) # if we ask a new one the pool is full try: with cm.connection('dn', 'pass'): pass except MaxConnectionReachedError: pass else: raise AssertionError() # down to one active self.assertFalse(cm._pool[1].active) self.assertTrue(cm._pool[0].active) # if we ask a new one the pool is full # but we get the inactive one with cm.connection('dn', 'pass'): self.assertEqual(len(cm), 2) self.assertFalse(cm._pool[1].active) self.assertTrue(cm._pool[0].active) # if we ask a new one the pool is full # but we get the inactive one, and rebind it with cm.connection('dn2', 'pass'): self.assertEqual(len(cm), 2) # the pool is still 2 self.assertEqual(len(cm), 2) # every connector is marked inactive self.assertFalse(cm._pool[0].active) self.assertFalse(cm._pool[1].active)
def __init__(self, ldapuri, sqluri, use_tls=False, bind_user='******', bind_password='******', admin_user='******', admin_password='******', users_root='ou=users,dc=mozilla', users_base_dn=None, pool_size=100, pool_recycle=3600, reset_on_return=True, single_box=False, ldap_timeout=-1, nodes_scheme='https', check_account_state=True, create_tables=False, ldap_pool_size=10, ldap_use_pool=False, connector_cls=StateConnector, check_node=False, ldap_max_lifetime=600, **kw): self.check_account_state = check_account_state self.ldapuri = ldapuri self.sqluri = sqluri self.bind_user = bind_user self.bind_password = bind_password self.admin_user = admin_user self.admin_password = admin_password self.use_tls = use_tls self.users_root = users_root self.users_base_dn = users_base_dn self.single_box = single_box self.nodes_scheme = nodes_scheme self.ldap_timeout = ldap_timeout # by default, the ldap connections use the bind user self.conn = ConnectionManager(ldapuri, bind_user, bind_password, use_tls=use_tls, timeout=ldap_timeout, size=ldap_pool_size, use_pool=ldap_use_pool, connector_cls=connector_cls, max_lifetime=ldap_max_lifetime) sqlkw = {'pool_size': int(pool_size), 'pool_recycle': int(pool_recycle), 'logging_name': 'weaveserver'} if self.sqluri is not None: driver = urlparse.urlparse(self.sqluri).scheme.lower() if "mysql" in driver: sqlkw['pool_reset_on_return'] = reset_on_return engine = create_engine(sqluri, **sqlkw) for table in tables: table.metadata.bind = engine if create_tables: table.create(checkfirst=True) else: engine = None self.check_node = check_node self.logger = CLIENT_HOLDER.default_client ResetCodeManager.__init__(self, engine, create_tables=create_tables)
def test_pool(self): if not LDAP: return dn = 'uid=adminuser,ou=logins,dc=mozilla' passwd = 'adminuser' pool = ConnectionManager('ldap://localhost', dn, passwd, use_pool=True) workers = [LDAPWorker(pool) for i in range(10)] for worker in workers: worker.start() for worker in workers: worker.join() self.assertEquals(len(worker.results), 10) cn = worker.results[0][0][1]['cn'] self.assertEquals(cn, ['admin'])
class LDAPUser(object): """LDAP authentication.""" def __init__(self, ldapuri, allow_new_users=True, users_root='ou=users,dc=mozilla', check_account_state=True, ldap_timeout=10, search_root='dc=mozilla', **kw): self.allow_new_users = allow_new_users self.check_account_state = check_account_state self.users_root = users_root self.search_root = search_root self.ldap_timeout = ldap_timeout self.logger = CLIENT_HOLDER.default_client kw.pop("check_node", None) self.conn = ConnectionManager(ldapuri, **kw) def _conn(self, bind=None, passwd=None): return self.conn.connection(bind, passwd) def _purge_conn(self, bind, passwd=None): self.conn.purge(bind, passwd=None) def get_user_id(self, user): """Returns the id for a user name""" if user.get('userid'): return user['userid'] #getting the dn gets it as a side effect self._get_dn(user) return user.get('userid') def create_user(self, user_name, password, email): """Creates a user. Returns a user object on success.""" if not self.allow_new_users: raise BackendError("Creation of new users is disabled") # no unicode user_name = user_name.encode('utf8') password = password.encode('utf8') email = email.encode('utf8') #First make sure the username isn't taken. There'll still be a race #condition, but it's pretty small test_user = User() test_user['username'] = user_name dn = self._get_dn(test_user) if dn is not None: return False user_id = self._get_next_user_id() password_hash = ssha(password) key = '%s%s' % (random.randint(0, 9999999), user_name) key = sha1(key).hexdigest() user = { 'cn': user_name, 'sn': user_name, 'uid': user_name, 'uidNumber': str(user_id), 'userPassword': password_hash, 'primaryNode': 'weave:', 'accountStatus': '1', 'account-enabled': 'Yes', 'mail': email, 'mail-verified': key, 'objectClass': ['dataStore', 'inetOrgPerson'] } dn = "uidNumber=%i,%s" % (user_id, self.users_root) #need a copy with some of the info for the return value userobj = User() userobj['username'] = user['uid'] userobj['userid'] = user['uidNumber'] userobj['mail'] = email userobj['dn'] = dn #need to turn the user hash into tuples user = user.items() with self._conn() as conn: try: res, __ = conn.add_s(dn, user) except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: self.logger.debug('Could not create the user.') raise BackendError(str(e)) if res == ldap.RES_ADD: return userobj else: return False
class LDAPAuth(ResetCodeManager): """LDAP authentication.""" def __init__(self, ldapuri, sqluri, use_tls=False, bind_user='******', bind_password='******', admin_user='******', admin_password='******', users_root='ou=users,dc=mozilla', users_base_dn=None, pool_size=100, pool_recycle=3600, reset_on_return=True, single_box=False, ldap_timeout=-1, nodes_scheme='https', check_account_state=True, create_tables=False, ldap_pool_size=10, ldap_use_pool=False, connector_cls=StateConnector, check_node=False, ldap_max_lifetime=600, **kw): self.check_account_state = check_account_state self.ldapuri = ldapuri self.sqluri = sqluri self.bind_user = bind_user self.bind_password = bind_password self.admin_user = admin_user self.admin_password = admin_password self.use_tls = use_tls self.users_root = users_root self.users_base_dn = users_base_dn self.single_box = single_box self.nodes_scheme = nodes_scheme self.ldap_timeout = ldap_timeout # by default, the ldap connections use the bind user self.conn = ConnectionManager(ldapuri, bind_user, bind_password, use_tls=use_tls, timeout=ldap_timeout, size=ldap_pool_size, use_pool=ldap_use_pool, connector_cls=connector_cls, max_lifetime=ldap_max_lifetime) sqlkw = { 'pool_size': int(pool_size), 'pool_recycle': int(pool_recycle), 'logging_name': 'weaveserver' } if self.sqluri is not None: driver = urlparse.urlparse(self.sqluri).scheme.lower() if "mysql" in driver: sqlkw['pool_reset_on_return'] = reset_on_return engine = create_engine(sqluri, **sqlkw) for table in tables: table.metadata.bind = engine if create_tables: table.create(checkfirst=True) else: engine = None self.check_node = check_node self.logger = CLIENT_HOLDER.default_client ResetCodeManager.__init__(self, engine, create_tables=create_tables) def _conn(self, bind=None, passwd=None): return self.conn.connection(bind, passwd) def _purge_conn(self, bind, passwd=None): self.conn.purge(bind, passwd=None) def _get_dn_by_filter(self, filter): dn = self.users_root scope = ldap.SCOPE_SUBTREE with self._conn() as conn: try: user = conn.search_st(dn, scope, filterstr=filter, attrlist=[], timeout=self.ldap_timeout) except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: self.logger.debug('Could not get the user info from ldap') raise BackendError(str(e)) except ldap.NO_SUCH_OBJECT: return None
def __init__(self, ldapuri, sqluri, use_tls=False, bind_user='******', bind_password='******', admin_user='******', admin_password='******', users_root='ou=users,dc=mozilla', users_base_dn=None, pool_size=100, pool_recycle=3600, reset_on_return=True, single_box=False, ldap_timeout=-1, nodes_scheme='https', check_account_state=True, create_tables=False, ldap_pool_size=10, ldap_use_pool=False, connector_cls=StateConnector, check_node=False, ldap_max_lifetime=600, **kw): self.check_account_state = check_account_state self.ldapuri = ldapuri self.sqluri = sqluri self.bind_user = bind_user self.bind_password = bind_password self.admin_user = admin_user self.admin_password = admin_password self.use_tls = use_tls self.users_root = users_root self.users_base_dn = users_base_dn self.single_box = single_box self.nodes_scheme = nodes_scheme self.ldap_timeout = ldap_timeout # by default, the ldap connections use the bind user self.conn = ConnectionManager(ldapuri, bind_user, bind_password, use_tls=use_tls, timeout=ldap_timeout, size=ldap_pool_size, use_pool=ldap_use_pool, connector_cls=connector_cls, max_lifetime=ldap_max_lifetime) sqlkw = { 'pool_size': int(pool_size), 'pool_recycle': int(pool_recycle), 'logging_name': 'weaveserver' } if self.sqluri is not None: driver = urlparse.urlparse(self.sqluri).scheme.lower() if "mysql" in driver: sqlkw['pool_reset_on_return'] = reset_on_return engine = create_engine(sqluri, **sqlkw) for table in tables: table.metadata.bind = engine if create_tables: table.create(checkfirst=True) else: engine = None self.check_node = check_node self.logger = CLIENT_HOLDER.default_client ResetCodeManager.__init__(self, engine, create_tables=create_tables)
class LDAPUser(object): """LDAP authentication.""" def __init__(self, ldapuri, users_root='ou=users,dc=mozilla', check_account_state=True, ldap_timeout=10, search_root='dc=mozilla', **kw): self.check_account_state = check_account_state self.users_root = users_root self.search_root = search_root self.ldap_timeout = ldap_timeout self.conn = ConnectionManager(ldapuri, **kw) def _conn(self, bind=None, passwd=None): return self.conn.connection(bind, passwd) def _purge_conn(self, bind, passwd=None): self.conn.purge(bind, passwd=None) def get_user_id(self, user): """Returns the id for a user name""" if user.get('userid'): return user['userid'] #getting the dn gets it as a side effect self._get_dn(user) return user.get('userid') def create_user(self, user_name, password, email): """Creates a user. Returns a user object on success.""" user_name = str(user_name) # XXX only ASCII #First make sure the username isn't taken. There'll still be a race #condition, but it's pretty small test_user = User() test_user['username'] = user_name dn = self._get_dn(test_user) if dn is not None: return False user_id = self._get_next_user_id() password_hash = ssha(password) key = '%s%s' % (random.randint(0, 9999999), user_name) key = sha1(key).hexdigest() user = {'cn': user_name, 'sn': user_name, 'uid': user_name, 'uidNumber': str(user_id), 'userPassword': password_hash, 'primaryNode': 'weave:', 'accountStatus': '1', 'account-enabled': 'Yes', 'mail': email, 'mail-verified': key, 'objectClass': ['dataStore', 'inetOrgPerson']} dn = "uidNumber=%i,%s" % (user_id, self.users_root) #need a copy with some of the info for the return value userobj = User() userobj['username'] = user['uid'] userobj['userid'] = user['uidNumber'] userobj['mail'] = email userobj['dn'] = dn #need to turn the user hash into tuples user = user.items() with self._conn() as conn: try: res, __ = conn.add_s(dn, user) except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: logger.debug('Could not create the user.') raise BackendError(str(e)) if res == ldap.RES_ADD: return userobj else: return False
class LDAPAuth(ResetCodeManager): """LDAP authentication.""" def __init__(self, ldapuri, sqluri, use_tls=False, bind_user='******', bind_password='******', admin_user='******', admin_password='******', users_root='ou=users,dc=mozilla', users_base_dn=None, pool_size=100, pool_recycle=3600, reset_on_return=True, single_box=False, ldap_timeout=-1, nodes_scheme='https', check_account_state=True, create_tables=False, ldap_pool_size=10, ldap_use_pool=False, connector_cls=StateConnector, check_node=False, ldap_max_lifetime=600, **kw): self.check_account_state = check_account_state self.ldapuri = ldapuri self.sqluri = sqluri self.bind_user = bind_user self.bind_password = bind_password self.admin_user = admin_user self.admin_password = admin_password self.use_tls = use_tls self.users_root = users_root self.users_base_dn = users_base_dn self.single_box = single_box self.nodes_scheme = nodes_scheme self.ldap_timeout = ldap_timeout # by default, the ldap connections use the bind user self.conn = ConnectionManager(ldapuri, bind_user, bind_password, use_tls=use_tls, timeout=ldap_timeout, size=ldap_pool_size, use_pool=ldap_use_pool, connector_cls=connector_cls, max_lifetime=ldap_max_lifetime) sqlkw = {'pool_size': int(pool_size), 'pool_recycle': int(pool_recycle), 'logging_name': 'weaveserver'} if self.sqluri is not None: driver = urlparse.urlparse(self.sqluri).scheme.lower() if "mysql" in driver: sqlkw['pool_reset_on_return'] = reset_on_return engine = create_engine(sqluri, **sqlkw) for table in tables: table.metadata.bind = engine if create_tables: table.create(checkfirst=True) else: engine = None self.check_node = check_node self.logger = CLIENT_HOLDER.default_client ResetCodeManager.__init__(self, engine, create_tables=create_tables) def _conn(self, bind=None, passwd=None): return self.conn.connection(bind, passwd) def _purge_conn(self, bind, passwd=None): self.conn.purge(bind, passwd=None) def _get_dn_by_filter(self, filter): dn = self.users_root scope = ldap.SCOPE_SUBTREE with self._conn() as conn: try: user = conn.search_st(dn, scope, filterstr=filter, attrlist=[], timeout=self.ldap_timeout) except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: self.logger.debug('Could not get the user info from ldap') raise BackendError(str(e)) except ldap.NO_SUCH_OBJECT: return None