[ldapfeed] do not crash on ldap user deletion + pull + already deactivated users, cleanups (closes #2392933)
--- a/server/serverctl.py Wed Jun 06 10:26:34 2012 +0200
+++ b/server/serverctl.py Wed Jun 06 10:30:54 2012 +0200
@@ -447,7 +447,7 @@
get_connection(
system['db-driver'], database=system['db-name'],
host=system.get('db-host'), port=system.get('db-port'),
- user=system.get('db-user'), password=system.get('db-password'),
+ user=system.get('db-user') or '', password=system.get('db-password') or '',
**extra)
except Exception, ex:
raise ConfigurationError(
--- a/server/sources/datafeed.py Wed Jun 06 10:26:34 2012 +0200
+++ b/server/sources/datafeed.py Wed Jun 06 10:30:54 2012 +0200
@@ -378,7 +378,6 @@
% (etype, ','.join(eids)))
def update_if_necessary(self, entity, attrs):
- self.notify_updated(entity)
entity.complete(tuple(attrs))
# check modification date and compare attribute values to only update
# what's actually needed
@@ -388,7 +387,7 @@
if v != getattr(entity, k))
if attrs:
entity.set_attributes(**attrs)
-
+ self.notify_updated(entity)
class DataFeedXMLParser(DataFeedParser):
--- a/server/test/unittest_ldapuser.py Wed Jun 06 10:26:34 2012 +0200
+++ b/server/test/unittest_ldapuser.py Wed Jun 06 10:30:54 2012 +0200
@@ -20,9 +20,8 @@
import os
import shutil
import time
-from os.path import abspath, join, exists
+from os.path import join, exists
import subprocess
-from socket import socket, error as socketerror
from logilab.common.testlib import TestCase, unittest_main, mock_object, Tags
@@ -32,13 +31,15 @@
from cubicweb.devtools.httptest import get_available_port
from cubicweb.devtools import get_test_db_handler
-from cubicweb.server.sources.ldapuser import *
+from cubicweb.server.session import security_enabled
+from cubicweb.server.sources.ldapuser import GlobTrFunc, UnknownEid, RQL2LDAPFilter
CONFIG = u'user-base-dn=ou=People,dc=cubicweb,dc=test'
URL = None
-def create_slapd_configuration(config):
- global slapd_process, URL
+def create_slapd_configuration(cls):
+ global URL
+ config = cls.config
basedir = join(config.apphome, "ldapdb")
slapdconf = join(config.apphome, "slapd.conf")
confin = file(join(config.apphome, "slapd.conf.in")).read()
@@ -60,28 +61,26 @@
ldapuri = 'ldap://%s' % host
cmdline = ["/usr/sbin/slapd", "-f", slapdconf, "-h", ldapuri, "-d", "0"]
config.info('Starting slapd:', ' '.join(cmdline))
- slapd_process = subprocess.Popen(cmdline)
+ cls.slapd_process = subprocess.Popen(cmdline)
time.sleep(0.2)
- if slapd_process.poll() is None:
- config.info('slapd started with pid %s' % slapd_process.pid)
+ if cls.slapd_process.poll() is None:
+ config.info('slapd started with pid %s' % cls.slapd_process.pid)
else:
raise EnvironmentError('Cannot start slapd with cmdline="%s" (from directory "%s")' %
(" ".join(cmdline), os.getcwd()))
URL = u'ldap://%s' % host
-def terminate_slapd(config):
- global slapd_process
- if slapd_process.returncode is None:
+def terminate_slapd(cls):
+ config = cls.config
+ if cls.slapd_process and cls.slapd_process.returncode is None:
config.info('terminating slapd')
- if hasattr(slapd_process, 'terminate'):
- slapd_process.terminate()
+ if hasattr(cls.slapd_process, 'terminate'):
+ cls.slapd_process.terminate()
else:
import os, signal
- os.kill(slapd_process.pid, signal.SIGTERM)
- slapd_process.wait()
+ os.kill(cls.slapd_process.pid, signal.SIGTERM)
+ cls.slapd_process.wait()
config.info('DONE')
- del slapd_process
-
class LDAPTestBase(CubicWebTC):
loglevel = 'ERROR'
@@ -90,11 +89,11 @@
def setUpClass(cls):
from cubicweb.cwctl import init_cmdline_log_threshold
init_cmdline_log_threshold(cls.config, cls.loglevel)
- create_slapd_configuration(cls.config)
+ create_slapd_configuration(cls)
@classmethod
def tearDownClass(cls):
- terminate_slapd(cls.config)
+ terminate_slapd(cls)
class DeleteStuffFromLDAPFeedSourceTC(LDAPTestBase):
test_db_id = 'ldap-feed'
@@ -108,24 +107,36 @@
lfsource = isession.repo.sources_by_uri['ldapuser']
stats = lfsource.pull_data(isession, force=True, raise_on_error=True)
+ def _pull(self):
+ with self.session.repo.internal_session() as isession:
+ with security_enabled(isession, read=False, write=False):
+ lfsource = isession.repo.sources_by_uri['ldapuser']
+ stats = lfsource.pull_data(isession, force=True, raise_on_error=True)
+ isession.commit()
+
def test_delete(self):
+ """ delete syt, pull, check deactivation, repull,
+ readd syt, pull, check activation
+ """
uri = self.repo.sources_by_uri['ldapuser'].urls[0]
- from subprocess import call
deletecmd = ("ldapdelete -H %s 'uid=syt,ou=People,dc=cubicweb,dc=test' "
"-v -x -D cn=admin,dc=cubicweb,dc=test -w'cw'" % uri)
os.system(deletecmd)
- isession = self.session.repo.internal_session(safe=False)
- from cubicweb.server.session import security_enabled
- with security_enabled(isession, read=False, write=False):
- lfsource = isession.repo.sources_by_uri['ldapuser']
- stats = lfsource.pull_data(isession, force=True, raise_on_error=True)
- isession.commit()
+ self._pull()
self.assertRaises(AuthenticationError, self.repo.connect, 'syt', password='syt')
self.assertEqual(self.execute('Any N WHERE U login "syt", '
'U in_state S, S name N').rows[0][0],
'deactivated')
-
-
+ # check that it doesn't choke
+ self._pull()
+ # reset the fscking ldap thing
+ self.tearDownClass()
+ self.setUpClass()
+ self._pull()
+ # still deactivated, but a warning has been emitted ...
+ self.assertEqual(self.execute('Any N WHERE U login "syt", '
+ 'U in_state S, S name N').rows[0][0],
+ 'deactivated')
class LDAPFeedSourceTC(LDAPTestBase):
test_db_id = 'ldap-feed'
--- a/sobjects/ldapparser.py Wed Jun 06 10:26:34 2012 +0200
+++ b/sobjects/ldapparser.py Wed Jun 06 10:30:54 2012 +0200
@@ -67,9 +67,23 @@
self.warning('deactivate %s %s entities', len(eids), etype)
for eid in eids:
wf = session.entity_from_eid(eid).cw_adapt_to('IWorkflowable')
- wf.fire_transition('deactivate')
+ wf.fire_transition_if_possible('deactivate')
session.commit(free_cnxset=False)
+ def update_if_necessary(self, entity, attrs):
+ entity.complete(tuple(attrs))
+ if entity.__regid__ == 'CWUser':
+ wf = entity.cw_adapt_to('IWorkflowable')
+ if wf.state == 'deactivated':
+ self.warning('update on deactivated user %s', entity.login)
+ mdate = attrs.get('modification_date')
+ if not mdate or mdate > entity.modification_date:
+ attrs = dict( (k, v) for k, v in attrs.iteritems()
+ if v != getattr(entity, k))
+ if attrs:
+ entity.set_attributes(**attrs)
+ self.notify_updated(entity)
+
def ldap2cwattrs(self, sdict, tdict=None):
if tdict is None:
tdict = {}