{"id":13821050,"url":"https://github.com/peppelinux/pyMultiLDAP","last_synced_at":"2025-05-16T12:32:23.139Z","repository":{"id":143289856,"uuid":"197207025","full_name":"peppelinux/pyMultiLDAP","owner":"peppelinux","description":"OpenLDAP proxy or simple python3 LDAP client to handle multiple LDAP connections, data aggregation and manipulation strategies","archived":false,"fork":false,"pushed_at":"2023-05-28T16:19:38.000Z","size":52,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-16T14:18:40.539Z","etag":null,"topics":["backend","gevent","json","ldap-client","ldap3","openldap","proxy","rewrite-rules","slapd","slapd-sock","unix-domain-socket"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peppelinux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-16T14:12:22.000Z","updated_at":"2025-02-07T09:38:15.000Z","dependencies_parsed_at":"2024-05-29T12:12:43.439Z","dependency_job_id":"7647fe1f-f83e-4e24-8d33-078bc6fa82f8","html_url":"https://github.com/peppelinux/pyMultiLDAP","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2FpyMultiLDAP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2FpyMultiLDAP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2FpyMultiLDAP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2FpyMultiLDAP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peppelinux","download_url":"https://codeload.github.com/peppelinux/pyMultiLDAP/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254530371,"owners_count":22086600,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","gevent","json","ldap-client","ldap3","openldap","proxy","rewrite-rules","slapd","slapd-sock","unix-domain-socket"],"created_at":"2024-08-04T08:01:14.359Z","updated_at":"2025-05-16T12:32:18.130Z","avatar_url":"https://github.com/peppelinux.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"pyMultiLDAP\n-----\n\npyMultiLDAP can gather data from multiple LDAP servers, can do data aggregation and manipulation with rewrite rules.\npyMultiLDAP can act also as a proxy server, behind openldap's slapd-sock backend or any custom implementation.\n\n### Features\n\n- LDAP client to many servers as a single one;\n- Custom functions to manipulate returning data (rewrite rules);\n- Export data in python dictionary, json or ldiff format;\n- Proxy Server, exposing a server daemon usable with [slapd-sock backend](https://www.openldap.org/software/man.cgi?query=slapd-sock).\n\npyMultiLDAP doesn't write to LDAP servers, it just handle readonly data.\nIt's also used to automate smart data processing on-the-fly.\n\nSee `example/settings.py.example` and `multildap/attr_rewrite.py` to understand how to configure and extend it.\n\n### Tested on\n\n- Debian9;\n- Debian10.\n\n### Setup\nConfigure multiple connections and search paramenters in `settings.py`.\n\nInstall\n````\ngit clone https://github.com/peppelinux/pyMultiLDAP.git\ncd pyMultiLDAP\npip install -r requirements\npython3 setup.py install\n````\n\nor use pipy [WIP]\n\n````\npip install pyMultiLDAP\n````\n\n#### LdapClient Class usage\n````\nfrom multildap.client import LdapClient\nfrom settings import LDAP_CONNECTIONS\n\nlc = LdapClient(LDAP_CONNECTIONS['SAMVICE'])\n\n# get all the results\nlc.get()\n\n# apply a filter\nlc.get(search=\"(\u0026(sn=de marco)(schacPersonalUniqueId=*DMRGPP83*))\")\n````\n\n##### Search and get\n\nSee `examples/run_test.py`.\n\nDifference between `.search` and `.get`:\n- *search* relyies on connection configuration and returns result as it come (raw);\n- *get* handles custom search filter and retrieve result as dictionary, json, ldif or python object format. It also apply rewrite rules.\n\n````\nimport copy\n\nfrom multildap.client import LdapClient\nfrom settings import LDAP_CONNECTIONS\n\nlc = LdapClient(LDAP_CONNECTIONS['DEFAULT'])\n\nkwargs = copy.copy(lc.conf)\nkwargs['search']['search_filter'] = \"(\u0026(sn=de medici)(givenName=aurora))\"\nr = lc.search(**kwargs['search'])\n````\n\n#### Results in json format\n````\nfrom multildap.client import LdapClient\nfrom . settings import LDAP_CONNECTIONS\n\n\nfor i in LDAP_CONNECTIONS:\n    lc = LdapClient(LDAP_CONNECTIONS[i])\n    print('# Results from: {} ...'.format(lc))\n\n    # get all as defined search_filter configured in settings connection\n    # but in json format\n    r = lc.get(format='json')\n    print(r)\n\n    # set a custom search as method argument\n    r = lc.get(search=\"(\u0026(sn=de marco)(schacPersonalUniqueId=*DMRGPP345tg86H))\", format='json')\n    print(r)\n\n    print('# End {}'.format(i))\n````\n\n#### Run the server\n\nNetwork address\n````\nmultildapd.py -conf settings.py -port 1234\n````\n\nUnix domain socket (for slapd-sock backend)\n````\nmultildapd.py -conf ./settings.py -loglevel \"DEBUG\" -socket /var/run/multildap.sock -pid /var/run/multildap.pid -uid openldap\n````\n\nDummy test without any ldap client connection configured, just to test slapd-sock:\n````\nmultildapd.py -conf ./settings.py -dummy -loglevel \"DEBUG\" -socket /var/run/multildap.sock -pid /var/run/multildap.pid\n````\n\nTest Unix domain socket from cli\n````\nnc -U /tmp/multildap.sock\n````\n\n#### Interfacing it with OpenLDAP slapd-sock\n\nThe  [Slapd-sock](https://www.openldap.org/software/man.cgi?query=slapd-sock)\n backend  to  slapd  uses  an external program to handle\n queries. This makes it\n possible to have a pool of processes, which persist  between  requests.\n This  allows  multithreaded operation and a higher level of efficiency.\n Multildapd  listens  on  a  Unix  domain  socket and it must have  been  started  independently;\n\nThis  module  may  also  be  used  as  an  overlay on top of some other\n database.  Use as an overlay allows external actions to be triggered in\n response to operations on the main database.\n\n#### Configure slapd-sock as database\n\nAdd the module.\n````\nldapadd -Y EXTERNAL -H ldapi:/// \u003c\u003cEOF\ndn: cn=module,cn=config\nobjectClass: olcModuleList\ncn: module\nolcModuleLoad: back_sock.la\nEOF\n````\n\nCreate the database.\n````\nldapadd -Y EXTERNAL -H ldapi:/// \u003c\u003cEOF\ndn: olcDatabase={4}sock,cn=config\nobjectClass: olcDbSocketConfig\nolcDatabase: {4}sock\nolcDbSocketPath: /var/run/multildap.sock\nolcSuffix: dc=proxy,dc=testunical,dc=it\nolcDbSocketExtensions: binddn peername ssf\nEOF\n````\n\nAdd an Overlay if you want to wrap an existing backend\n````\nldapmodify -H ldapi:// -Y EXTERNAL \u003c\u003cEOF\ndn: olcOverlay=sock,olcDatabase={1}mdb,cn=config\nchangetype: add\nobjectClass: olcConfig\nobjectClass: olcOverlayConfig\nobjectClass: olcOvSocketConfig\nolcOverlay: sock\nolcDbSocketPath: /var/run/multildap/multildap.sock\nolcOvSocketOps: bind unbind search\nolcOvSocketResps: search\nEOF\n````\n\nRemember to configure an ACL otherwise only `ldapsearch -H ldapi:// -Y EXTERNAL` as root would fetch ldif.\nRemember to add a space char `' '` after every olaAccess line, otherwise you'll get `Implementation specific error(80)`.\n\n````\nexport BASEDC=\"dc=testunical,dc=it\"\n\nldapadd -Y EXTERNAL -H ldapi:/// \u003c\u003cEOF\ndn: olcDatabase={4}sock,cn=config\nchangeType: modify\nreplace: olcAccess\nolcAccess: to *\n by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage\n by * break\n# the following permits self BIND by users\nolcAccess: to dn.subtree=\"dc=proxy,$BASEDC\"\n by self read\n by * break\n# the following two permits SEARCH by idp and foreign auth system\nolcAccess: to dn.subtree=\"ou=people,$BASEDC\"\n by dn.children=\"ou=auth,$BASEDC\" read\n by self read\n by * break\nolcAccess: to dn.subtree=\"ou=people,$BASEDC\"\n by dn.children=\"ou=idp,$BASEDC\" read\n by self read\n by * break\nolcAccess: to *\n by anonymous auth\n by * break\nEOF\n````\n\nAuthentication  (BIND) on top of the multildapd must be configured with attribute\n`rewrite_dn_to` regarding every connections in the settings.py. If abstent the specified connection will be excluded from authentication.\nTODO: _adopt openldap proxy authz statements_.\n\n````\nldapsearch -H ldap://localhost:389 -D \"uid=peppe,dc=proxy,dc=testunical,dc=it\" -w thatsecret -b 'uid=peppe,dc=proxy,dc=unical,dc=it'\n````\n\n#### Hints\n\nSee databases currently installed:\n- `ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn=config' -LLL  \"olcDatabase=*\"`;\n- Use `client_strategy = RESTARTABLE` instead of `REUSABLE` in your settings.py for better performances;\n- A Backend can not be deleted via ldapdelete/modify until OpenLDAP 2.5 will be released;\n- Changing the socket path\n````\nldapmodify -Y EXTERNAL -H ldapi:/// \u003c\u003cEOF\ndn: olcDatabase={4}sock,cn=config\nchangetype: modify\nreplace: olcDbSocketPath\nolcDbSocketPath: /var/run/multildap.sock\nEOF\n````\n- Deploy a dummy socket listener with socat, just to debug incoming connection from slapd-sock.\n\n````\nsocat -s UNIX-LISTEN:/tmp/slapd-sock,umask=000,fork EXEC:\"$your_command\"\n````\n\n#### Other slapd-sock resources:\n\n- [slapsock](https://build.opensuse.org/package/show/home:stroeder:AE-DIR/python-slapdsock)\n- [slapd-trigger](https://github.com/jclain/slapd-trigger)\n- [ldap.h search scopes](https://github.com/openldap/openldap/blob/master/include/ldap.h#L581)\n- [slapd-sock in OpenLDAP ML](https://www.openldap.org/cgi-bin/wilma_glimpse/openldap-technical?query=slapd-sock\u0026Search=Search\u0026errors=0\u0026maxfiles=50\u0026maxlines=10\u0026.cgifields=lineonly\u0026.cgifields=restricttofiles\u0026.cgifields=filelist\u0026.cgifields=partial\u0026.cgifields=case)\n\n\n#### Todo\n\n- Example configuration with slapd's Proxy Authorization Rules (authzTo: dn.regex:^uid=[^,]*,dc=example,dc=com$);\n- Only SEARCH, BIND and UNBIND is usable, other LDAP methods should be implemented;\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeppelinux%2FpyMultiLDAP","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeppelinux%2FpyMultiLDAP","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeppelinux%2FpyMultiLDAP/lists"}