|
| 1 | +## This file is part of Invenio. |
| 2 | +## Copyright (C) 2009, 2010, 2011, 2014 CERN. |
| 3 | +## |
| 4 | +## Invenio is free software; you can redistribute it and/or |
| 5 | +## modify it under the terms of the GNU General Public License as |
| 6 | +## published by the Free Software Foundation; either version 2 of the |
| 7 | +## License, or (at your option) any later version. |
| 8 | +## |
| 9 | +## Invenio is distributed in the hope that it will be useful, but |
| 10 | +## WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | +## General Public License for more details. |
| 13 | +## |
| 14 | +## You should have received a copy of the GNU General Public License |
| 15 | +## along with Invenio; if not, write to the Free Software Foundation, Inc., |
| 16 | +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
| 17 | + |
| 18 | +"""Invenio LDAP interface for CERN. """ |
| 19 | + |
| 20 | +from time import sleep |
| 21 | +from thread import get_ident |
| 22 | + |
| 23 | +import ldap |
| 24 | +import ldap.filter |
| 25 | + |
| 26 | +CFG_CERN_LDAP_URI = "ldap://xldap.cern.ch:389" |
| 27 | +CFG_CERN_LDAP_BASE = "OU=Users,OU=Organic Units,DC=cern,DC=ch" |
| 28 | + |
| 29 | +_ldap_connection_pool = {} |
| 30 | + |
| 31 | + |
| 32 | +def _cern_ldap_login(): |
| 33 | + """Get a connection from _ldap_connection_pool or create a new one""" |
| 34 | + try: |
| 35 | + connection = _ldap_connection_pool[get_ident()] |
| 36 | + except KeyError: |
| 37 | + connection = _ldap_connection_pool[get_ident()] = ldap.initialize(CFG_CERN_LDAP_URI) |
| 38 | + return connection |
| 39 | + |
| 40 | + |
| 41 | +def _sanitize_input(query): |
| 42 | + """ |
| 43 | + Take the query, filter it through ldap.filter.escape_filter_chars and |
| 44 | + replace the dots with spaces. |
| 45 | + """ |
| 46 | + query = ldap.filter.escape_filter_chars(query) |
| 47 | + query = query.replace(".", " ") |
| 48 | + return query |
| 49 | + |
| 50 | + |
| 51 | +def get_users_info_by_displayName(displayName): |
| 52 | + """ |
| 53 | + Query the CERN LDAP server for information about all users whose name |
| 54 | + contains the displayName. |
| 55 | + Return a list of user dictionaries (or empty list). |
| 56 | + """ |
| 57 | + |
| 58 | + connection = _cern_ldap_login() |
| 59 | + |
| 60 | + # Split displayName and add each part of it to the search query |
| 61 | + if displayName: |
| 62 | + query = _sanitize_input(displayName) |
| 63 | + query_elements = query.split() |
| 64 | + query_filter = "& " |
| 65 | + for element in query_elements: |
| 66 | + query_filter += '(displayName=*%s*) ' % element |
| 67 | + # Query will look like that: "(& (displayName=*john*) (displayName=*smith*)" |
| 68 | + # Eliminate the secondary accounts (aliases, etc.) |
| 69 | + query_filter = "(& (%s) (| (employeetype=primary) (employeetype=external) (employeetype=ExCern) ) )" % query_filter |
| 70 | + else: |
| 71 | + return [] |
| 72 | + |
| 73 | + try: |
| 74 | + results = connection.search_st(CFG_CERN_LDAP_BASE, ldap.SCOPE_SUBTREE, |
| 75 | + query_filter, timeout=5) |
| 76 | + except ldap.LDAPError: |
| 77 | + ## Mmh.. connection error? Let's reconnect at least once just in case |
| 78 | + sleep(1) |
| 79 | + connection = _cern_ldap_login() |
| 80 | + try: |
| 81 | + results = connection.search_st(CFG_CERN_LDAP_BASE, ldap.SCOPE_SUBTREE, |
| 82 | + query_filter, timeout=5) |
| 83 | + except ldap.LDAPError: |
| 84 | + # Another error (maybe the LDAP query size is too big, etc.) |
| 85 | + # TODO, if it's needed, here we can return various different |
| 86 | + # information based on the error message |
| 87 | + results = [] |
| 88 | + return results |
| 89 | + |
| 90 | + |
| 91 | +def get_users_info_by_displayName_or_email(name): |
| 92 | + """ |
| 93 | + Query the CERN LDAP server for information about all users whose displayName |
| 94 | + or email contains the name. |
| 95 | + Return a list of user dictionaries (or empty list). |
| 96 | + """ |
| 97 | + |
| 98 | + connection = _cern_ldap_login() |
| 99 | + |
| 100 | + # Split name and add each part of it to the search query |
| 101 | + if name: |
| 102 | + query = _sanitize_input(name) |
| 103 | + query_elements = query.split() |
| 104 | + query_filter_name = "& " |
| 105 | + query_filter_email = "& " |
| 106 | + for element in query_elements: |
| 107 | + query_filter_name += '(displayName=*%s*) ' % element |
| 108 | + query_filter_email += '(mail=*%s*) ' % element |
| 109 | + # query_filter_name will look like that: |
| 110 | + # "(| (& (displayName=*john*) (displayName=*smith*)) (& (mail=*john*) (mail=*smith*)) )" |
| 111 | + # Eliminate the secondary accounts (aliases, etc.) |
| 112 | + query_filter = "(& (| (%s) (%s)) (| (employeetype=primary) (employeetype=external) (employeetype=ExCern) ) )" % (query_filter_name, query_filter_email) |
| 113 | + else: |
| 114 | + return [] |
| 115 | + |
| 116 | + try: |
| 117 | + results = connection.search_st(CFG_CERN_LDAP_BASE, ldap.SCOPE_SUBTREE, |
| 118 | + query_filter, timeout=5) |
| 119 | + except ldap.LDAPError: |
| 120 | + ## Mmh.. connection error? Let's reconnect at least once just in case |
| 121 | + sleep(1) |
| 122 | + connection = _cern_ldap_login() |
| 123 | + try: |
| 124 | + results = connection.search_st(CFG_CERN_LDAP_BASE, ldap.SCOPE_SUBTREE, |
| 125 | + query_filter, timeout=5) |
| 126 | + except ldap.LDAPError: |
| 127 | + # Another error (maybe the LDAP query size is too big, etc.) |
| 128 | + # TODO, if it's needed, here we can return various different |
| 129 | + # information based on the error message |
| 130 | + results = [] |
| 131 | + return results |
0 commit comments