# copyright 2011-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""cubicweb ldap feed sourceunlike ldapuser source, this source is copy based and will import ldap content(beside passwords for authentication) into the system source."""from__future__importwith_statementfromlogilab.common.decoratorsimportcachedfromlogilab.common.shellutilsimportgenerate_passwordfromcubicwebimportBinary,ConfigurationErrorfromcubicweb.server.utilsimportcrypt_passwordfromcubicweb.server.sourcesimportdatafeedclassDataFeedLDAPAdapter(datafeed.DataFeedParser):__regid__='ldapfeed'# attributes that may appears in source user_attrs dict which are not# attributes of the cw usernon_attribute_keys=set(('email',))defprocess(self,url,raise_on_error=False):"""IDataFeedParser main entry point"""source=self.sourcesearchstr='(&%s)'%''.join(source.base_filters)self.debug('processing ldapfeed stuff %s%s',source,searchstr)foruserdictinsource._search(self._cw,source.user_base_dn,source.user_base_scope,searchstr):self.warning('fetched user %s',userdict)entity=self.extid2entity(userdict['dn'],'CWUser',**userdict)ifentityisnotNoneandnotself.created_during_pull(entity):self.notify_updated(entity)attrs=self.ldap2cwattrs(userdict)self.update_if_necessary(entity,attrs)self._process_email(entity,userdict)defhandle_deletion(self,config,session,myuris):ifconfig['delete-entities']:super(DataFeedLDAPAdapter,self).handle_deletion(config,session,myuris)returnifmyuris:byetype={}forextid,(eid,etype)inmyuris.iteritems():ifself.is_deleted(extid,etype,eid):byetype.setdefault(etype,[]).append(str(eid))foretype,eidsinbyetype.iteritems():ifetype!='CWUser':continueself.warning('deactivate %s%s entities',len(eids),etype)foreidineids:wf=session.entity_from_eid(eid).cw_adapt_to('IWorkflowable')wf.fire_transition_if_possible('deactivate')session.commit(free_cnxset=False)defupdate_if_necessary(self,entity,attrs):# disable read security to allow password selectionwithentity._cw.security_enabled(read=False):entity.complete(tuple(attrs))ifentity.__regid__=='CWUser':wf=entity.cw_adapt_to('IWorkflowable')ifwf.state=='deactivated':self.warning('update on deactivated user %s',entity.login)mdate=attrs.get('modification_date')ifnotmdateormdate>entity.modification_date:attrs=dict((k,v)fork,vinattrs.iteritems()ifv!=getattr(entity,k))ifattrs:entity.set_attributes(**attrs)self.notify_updated(entity)defldap2cwattrs(self,sdict,tdict=None):iftdictisNone:tdict={}forsattr,tattrinself.source.user_attrs.iteritems():iftattrnotinself.non_attribute_keys:try:tdict[tattr]=sdict[sattr]exceptKeyError:raiseConfigurationError('source attribute %s is not present ''in the source, please check the ''user-attrs-map field'%sattr)returntdictdefbefore_entity_copy(self,entity,sourceparams):ifentity.__regid__=='EmailAddress':entity.cw_edited['address']=sourceparams['address']else:self.ldap2cwattrs(sourceparams,entity.cw_edited)pwd=entity.cw_edited.get('upassword')ifnotpwd:# generate a dumb password if not fetched from ldap (see# userPassword)pwd=crypt_password(generate_password())entity.cw_edited['upassword']=Binary(pwd)returnentitydefafter_entity_copy(self,entity,sourceparams):super(DataFeedLDAPAdapter,self).after_entity_copy(entity,sourceparams)ifentity.__regid__=='EmailAddress':returngroups=[self._get_group(n)forninself.source.user_default_groups]entity.set_relations(in_group=groups)self._process_email(entity,sourceparams)defis_deleted(self,extid,etype,eid):try:extid,_=extid.rsplit('@@',1)exceptValueError:passreturnnotself.source.object_exists_in_ldap(extid)def_process_email(self,entity,userdict):try:emailaddrs=userdict[self.source.user_rev_attrs['email']]exceptKeyError:return# no email for that user, nothing to doifnotisinstance(emailaddrs,list):emailaddrs=[emailaddrs]foremailaddrinemailaddrs:# search for existant email first, may be coming from another sourcerset=self._cw.execute('EmailAddress X WHERE X address %(addr)s',{'addr':emailaddr})ifnotrset:# not found, create it. first forge an external idemailextid=userdict['dn']+'@@'+emailaddremail=self.extid2entity(emailextid,'EmailAddress',address=emailaddr)ifentity.primary_email:entity.set_relations(use_email=email)else:entity.set_relations(primary_email=email)elifself.sourceuris:# pop from sourceuris anyway, else email may be removed by the# source once import is finisheduri=userdict['dn']+'@@'+emailaddr.encode('utf-8')self.sourceuris.pop(uri,None)# XXX else check use_email relation?@cacheddef_get_group(self,name):returnself._cw.execute('Any X WHERE X is CWGroup, X name %(name)s',{'name':name}).get_entity(0,0)