server/sources/ldapuser.py
branchstable
changeset 5603 d8d9f4ec252d
parent 5456 d040889fac4e
child 5604 60a92bf32a18
equal deleted inserted replaced
5602:277b15d6d3ed 5603:d8d9f4ec252d
   199         self._cache = {}
   199         self._cache = {}
   200         self._query_cache = TimedCache(2*60)
   200         self._query_cache = TimedCache(2*60)
   201 
   201 
   202     def init(self):
   202     def init(self):
   203         """method called by the repository once ready to handle request"""
   203         """method called by the repository once ready to handle request"""
       
   204         self.info('ldap init')
   204         self.repo.looping_task(self._interval, self.synchronize)
   205         self.repo.looping_task(self._interval, self.synchronize)
   205         self.repo.looping_task(self._query_cache.ttl.seconds/10,
   206         self.repo.looping_task(self._query_cache.ttl.seconds/10,
   206                                self._query_cache.clear_expired)
   207                                self._query_cache.clear_expired)
   207 
   208 
   208     def synchronize(self):
   209     def synchronize(self):
   219         try:
   220         try:
   220             cursor = session.system_sql("SELECT eid, extid FROM entities WHERE "
   221             cursor = session.system_sql("SELECT eid, extid FROM entities WHERE "
   221                                         "source='%s'" % self.uri)
   222                                         "source='%s'" % self.uri)
   222             for eid, b64extid in cursor.fetchall():
   223             for eid, b64extid in cursor.fetchall():
   223                 extid = b64decode(b64extid)
   224                 extid = b64decode(b64extid)
       
   225                 self.debug('ldap eid %s', eid)
   224                 # if no result found, _search automatically delete entity information
   226                 # if no result found, _search automatically delete entity information
   225                 res = self._search(session, extid, BASE)
   227                 res = self._search(session, extid, BASE)
       
   228                 self.debug('ldap search %s', res)
   226                 if res:
   229                 if res:
   227                     ldapemailaddr = res[0].get(ldap_emailattr)
   230                     ldapemailaddr = res[0].get(ldap_emailattr)
   228                     if ldapemailaddr:
   231                     if ldapemailaddr:
   229                         rset = execute('Any X,A WHERE '
   232                         rset = execute('Any X,A WHERE '
   230                                        'X address A, U use_email X, U eid %(u)s',
   233                                        'X address A, U use_email X, U eid %(u)s',
   267         defined in this source, else raise `AuthenticationError`
   270         defined in this source, else raise `AuthenticationError`
   268 
   271 
   269         two queries are needed since passwords are stored crypted, so we have
   272         two queries are needed since passwords are stored crypted, so we have
   270         to fetch the salt first
   273         to fetch the salt first
   271         """
   274         """
       
   275         self.info('ldap authenticate %s', login)
   272         if password is None:
   276         if password is None:
   273             raise AuthenticationError()
   277             raise AuthenticationError()
   274         searchfilter = [filter_format('(%s=%s)', (self.user_login_attr, login))]
   278         searchfilter = [filter_format('(%s=%s)', (self.user_login_attr, login))]
   275         searchfilter.extend([filter_format('(%s=%s)', ('objectClass', o))
   279         searchfilter.extend([filter_format('(%s=%s)', ('objectClass', o))
   276                              for o in self.user_classes])
   280                              for o in self.user_classes])
   341         """return result from this source for a rql query (actually from a rql
   345         """return result from this source for a rql query (actually from a rql
   342         syntax tree and a solution dictionary mapping each used variable to a
   346         syntax tree and a solution dictionary mapping each used variable to a
   343         possible type). If cachekey is given, the query necessary to fetch the
   347         possible type). If cachekey is given, the query necessary to fetch the
   344         results (but not the results themselves) may be cached using this key.
   348         results (but not the results themselves) may be cached using this key.
   345         """
   349         """
       
   350         self.debug('ldap syntax tree search')
   346         # XXX not handled : transform/aggregat function, join on multiple users...
   351         # XXX not handled : transform/aggregat function, join on multiple users...
   347         assert len(union.children) == 1, 'union not supported'
   352         assert len(union.children) == 1, 'union not supported'
   348         rqlst = union.children[0]
   353         rqlst = union.children[0]
   349         assert not rqlst.with_, 'subquery not supported'
   354         assert not rqlst.with_, 'subquery not supported'
   350         rqlkey = rqlst.as_string(kwargs=args)
   355         rqlkey = rqlst.as_string(kwargs=args)
   492         #conn.sasl_interactive_bind_s('', sasl.gssapi())
   497         #conn.sasl_interactive_bind_s('', sasl.gssapi())
   493 
   498 
   494     def _search(self, session, base, scope,
   499     def _search(self, session, base, scope,
   495                 searchstr='(objectClass=*)', attrs=()):
   500                 searchstr='(objectClass=*)', attrs=()):
   496         """make an ldap query"""
   501         """make an ldap query"""
       
   502         self.info('ldap search %s %s %s %s %s', self.uri, base, scope, searchstr, list(attrs))
   497         cnx = session.pool.connection(self.uri).cnx
   503         cnx = session.pool.connection(self.uri).cnx
   498         try:
   504         try:
   499             res = cnx.search_s(base, scope, searchstr, attrs)
   505             res = cnx.search_s(base, scope, searchstr, attrs)
   500         except ldap.PARTIAL_RESULTS:
   506         except ldap.PARTIAL_RESULTS:
   501             res = cnx.result(all=0)[1]
   507             res = cnx.result(all=0)[1]
   502         except ldap.NO_SUCH_OBJECT:
   508         except ldap.NO_SUCH_OBJECT:
       
   509             self.info('ldap NO SUCH OBJECT')
   503             eid = self.extid2eid(base, 'CWUser', session, insert=False)
   510             eid = self.extid2eid(base, 'CWUser', session, insert=False)
   504             if eid:
   511             if eid:
   505                 self.warning('deleting ldap user with eid %s and dn %s',
   512                 self.warning('deleting ldap user with eid %s and dn %s',
   506                              eid, base)
   513                              eid, base)
   507                 entity = session.entity_from_eid(eid, 'CWUser')
   514                 entity = session.entity_from_eid(eid, 'CWUser')
   539                     rec_dict[key] = value = value[0]
   546                     rec_dict[key] = value = value[0]
   540             rec_dict['dn'] = rec_dn
   547             rec_dict['dn'] = rec_dn
   541             self._cache[rec_dn] = rec_dict
   548             self._cache[rec_dn] = rec_dict
   542             result.append(rec_dict)
   549             result.append(rec_dict)
   543         #print '--->', result
   550         #print '--->', result
       
   551         self.info('ldap built results %s', result)
   544         return result
   552         return result
   545 
   553 
   546     def before_entity_insertion(self, session, lid, etype, eid):
   554     def before_entity_insertion(self, session, lid, etype, eid):
   547         """called by the repository when an eid has been attributed for an
   555         """called by the repository when an eid has been attributed for an
   548         entity stored here but the entity has not been inserted in the system
   556         entity stored here but the entity has not been inserted in the system
   549         table yet.
   557         table yet.
   550 
   558 
   551         This method must return the an Entity instance representation of this
   559         This method must return the an Entity instance representation of this
   552         entity.
   560         entity.
   553         """
   561         """
       
   562         self.info('ldap before entity insertion')
   554         entity = super(LDAPUserSource, self).before_entity_insertion(session, lid, etype, eid)
   563         entity = super(LDAPUserSource, self).before_entity_insertion(session, lid, etype, eid)
   555         res = self._search(session, lid, BASE)[0]
   564         res = self._search(session, lid, BASE)[0]
   556         for attr in entity.e_schema.indexable_attributes():
   565         for attr in entity.e_schema.indexable_attributes():
   557             entity[attr] = res[self.user_rev_attrs[attr]]
   566             entity[attr] = res[self.user_rev_attrs[attr]]
   558         return entity
   567         return entity
   559 
   568 
   560     def after_entity_insertion(self, session, dn, entity):
   569     def after_entity_insertion(self, session, dn, entity):
   561         """called by the repository after an entity stored here has been
   570         """called by the repository after an entity stored here has been
   562         inserted in the system table.
   571         inserted in the system table.
   563         """
   572         """
       
   573         self.info('ldap after entity insertion')
   564         super(LDAPUserSource, self).after_entity_insertion(session, dn, entity)
   574         super(LDAPUserSource, self).after_entity_insertion(session, dn, entity)
   565         for group in self.user_default_groups:
   575         for group in self.user_default_groups:
   566             session.execute('SET X in_group G WHERE X eid %(x)s, G name %(group)s',
   576             session.execute('SET X in_group G WHERE X eid %(x)s, G name %(group)s',
   567                             {'x': entity.eid, 'group': group})
   577                             {'x': entity.eid, 'group': group})
   568         # search for existant email first
   578         # search for existant email first