def search_dn(self): """Searches for the user's Distinguished Name in the LDAP directory. :returns: A tuple of (dn, canonical_username) """ uid_attr = escape_filter_chars(_config.get('ldap', 'uid_attr')) encoding = _config.get('ldap', 'encoding') manager = _config.get('ldap', 'manager').encode(encoding) manager_password = _config.get( 'ldap', 'manager_password', raw=True).encode(encoding) if manager: _logger.debug("Attempting authenticated bind as manager to %s", manager) self.ldap.simple_bind_s(manager, manager_password) filter_ = "(%s=%s)" % (uid_attr, escape_filter_chars(self.username)) result = self.ldap.search_s(_config.get('ldap', 'basedn'), ldap.SCOPE_SUBTREE, filter_) if not result or not result[0] or not result[0][0]: raise UserNotFound(filter_) user_dn, attrs = result[0] if uid_attr in attrs: uid = attrs[uid_attr][0].decode(encoding) else: uid = self.username return user_dn.decode(encoding), uid
def is_group_member(self, group_dn): """ Verify that uid is a member in the group object identified by group_dn, using the pre-initialized ldap object l. The full user DN will be attempted matched against the member attribute of the group object. If no match is found, the user uid will be attempted matched against the memberUid attribute. The former should work well for groupOfNames and groupOfUniqueNames objects, the latter should work for posixGroup objects. """ encoding = _config.get('ldap', 'encoding') user_dn = self.get_user_dn().encode(encoding) # Match groupOfNames/groupOfUniqueNames objects try: filterstr = '(member=%s)' % escape_filter_chars(user_dn) result = self.ldap.search_s(group_dn, ldap.SCOPE_BASE, filterstr) _logger.debug("groupOfNames results: %s", result) if len(result) < 1: # If no match, match posixGroup objects filterstr = ( '(memberUid=%s)' % escape_filter_chars(self.username.encode(encoding))) result = self.ldap.search_s(group_dn, ldap.SCOPE_BASE, filterstr) _logger.debug("posixGroup results: %s", result) return len(result) > 0 except ldap.TIMEOUT, error: _logger.error("Timed out while veryfing group memberships") raise TimeoutError(error)
def mk_filter(self): # we still need a custom mk_filter because this is an | query if attmap['member'] and 'memberUid' in self.parameters: memberuid = self.parameters['memberUid'] entry = passwd.uid2entry(self.conn, memberuid) if entry: return '(&%s(|(%s=%s)(%s=%s)))' % ( self.filter, attmap['memberUid'], escape_filter_chars(memberuid), attmap['member'], escape_filter_chars(entry[0]) ) return super(Search, self).mk_filter()
def login(request): """ Login page. This view is user as redirection target when an unconnected user queries a page that requires to be connected (@login_required decorator). """ login_failed = False if request.method == 'POST': # LDAP DN special characters are escaped in this arbitrary input username = escape_filter_chars(request.POST['username']) password = request.POST['inputPassword'] user = auth.authenticate(username=username, password=password) if user is not None and user.is_active: auth.login(request, user) if 'next' in request.GET: return HttpResponseRedirect(request.GET['next']) return HttpResponseRedirect("/") else: login_failed = True return render( request, "login.html", { 'request': request, 'login_failed': login_failed, })
def enableOrDisableAccount(self, domain, account, dn, action, accountTypeInLogger=None): self.domain = web.safestr(domain).strip().lower() self.account = web.safestr(account).strip().lower() self.dn = escape_filter_chars(web.safestr(dn)) # Validate operation action. if action in ["enable", "disable"]: self.action = action else: return (False, "INVALID_ACTION") # Set value of valid account status. if action == "enable": self.status = attrs.ACCOUNT_STATUS_ACTIVE else: self.status = attrs.ACCOUNT_STATUS_DISABLED try: self.updateAttrSingleValue(dn=self.dn, attr="accountStatus", value=self.status) if accountTypeInLogger is not None: web.logger( msg="%s %s: %s." % (str(action).capitalize(), str(accountTypeInLogger), self.account), domain=self.domain, event=self.action, ) return (True,) except ldap.LDAPError, e: return (False, ldaputils.getExceptionDesc(e))
def get_by_email(self, email): query = "(%s=%s)" % (self.attribute_mapping["mail"], ldap_filter.escape_filter_chars(email)) users = self.get_all(query) try: return users[0] except IndexError: return None
def get_by_email(self, email): users = self.get_all('(mail=%s)' % \ (ldap_filter.escape_filter_chars(email),)) try: return users[0] except IndexError: return None
def get_by_name(self, name, filter=None): # pylint: disable=W0221,W0613 search_filter = "(%s=%s)" % (self.attribute_mapping["name"], ldap_filter.escape_filter_chars(name)) tenants = self.get_all(search_filter) try: return tenants[0] except IndexError: raise exception.ProjectNotFound(project_id=name)
def get_by_name(self, name, filter=None): query = "(%s=%s)" % (self.attribute_mapping["name"], ldap_filter.escape_filter_chars(name)) groups = self.get_all(query) try: return groups[0] except IndexError: raise exception.GroupNotFound(group_id=name)
def get_by_name(self, name, filter=None): query = "(%s=%s)" % (self.attribute_mapping["name"], ldap_filter.escape_filter_chars(name)) res = self.get_all(query) try: return res[0] except IndexError: raise self._not_found(name)
def search_group(self, id, conn=None): if not conn: conn = self.connect() filter = self.options['group_filter'] % {'group': escape_filter_chars(id)} rs = conn.search_s(self.options['group_dn'], ldap.SCOPE_SUBTREE, filter) if rs: return rs[0]
def ingroup(request, mail, cn): # first, figure out the uid mail_filter = make_search_filter(dict(mail=mail)) alias_filter = make_search_filter(dict(emailAlias=mail)) search_filter = '(|{}{})'.format(mail_filter, alias_filter) rs = connection().search_s( settings.LDAP_SEARCH_BASE, ldap.SCOPE_SUBTREE, search_filter, ['uid'] ) uid = None for dn, result in rs: uid = result['uid'][0] break if not uid: return False search_filter = u""" (| (&(objectClass=groupOfNames)(cn=%(groupname)s)(member=%(dn)s)) (&(objectClass=posixGroup)(|(cn=scm_*)(cn=svn_*))(cn=%(groupname)s)(memberUid=%(mail)s)) (&(objectClass=posixGroup)(!(|(cn=scm_*)(cn=svn_*)))(cn=%(groupname)s)(memberUid=%(uid)s)) ) """ search_filter = search_filter % { 'groupname': escape_filter_chars(cn), 'dn': escape_filter_chars(dn), 'uid': escape_filter_chars(uid), 'mail': escape_filter_chars(mail), } search_filter = search_filter.strip() rs = connection().search_s( settings.GROUP_LDAP_SEARCH_BASE, ldap.SCOPE_SUBTREE, search_filter, ['cn'] ) for __ in rs: return True return False
def get_by_name(self, name, filter=None): users = self.get_all('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) try: return users[0] except IndexError: raise exception.UserNotFound(user_id=name)
def build_search_filter(self, term): # Note that this function might return an invalid filter if the config # use an incorrectly written custom filter. term_escaped = escape_filter_chars(term) if 'ldap_custom_filter' in self._config: return self._build_search_filter_from_custom_filter(term_escaped) else: return self._build_search_filter_from_searched_columns(term_escaped)
def get_by_name(self, name, filter=None): roles = self.get_all('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) try: return roles[0] except IndexError: raise exception.RoleNotFound(role_id=name)
def get_by_name(self, name, filter=None): users = self.get_all('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) try: return users[0] except IndexError: return None
def _gen_filter(attrtypes, values, extra=None): filt = '' for attr, value in zip(attrtypes, values): if attr is not None and value is not None: filt += '(%s=%s)' % (attr, ldap_filter.escape_filter_chars(value)) if extra is not None: filt += '{FILT}'.format(FILT=extra) return filt
def get_by_name(self, name, filter=None): query = ('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) users = self.get_all(query) try: return users[0] except IndexError: raise exception.UserNotFound(user_id=name)
def get_ldap_user_by_guid(self, guid): g = escape_filter_chars(guid, escape_mode=1) result = self.ldcon.search_s \ ( self.cfg.LDAP_BASE_DN , ldap.SCOPE_SUBTREE , '(&(objectGUID=%s)(objectclass=%s))' % (g, self.objectclass) , None ) return self._get_ldap_user(result)
def search_for_users(self, user_string, base=None, search_attributes=None, return_attributes=None, credentials=None, json_safe=False): """ Returns matching user objects as a list of dictionaries Args: user_string: The substring to search for base: Optionally override the base object's DN search_attributes: The attributes to search through, with binary data removed easyad.EasyAD.user_attributes by default return_attributes: A list of attributes to return. easyad.EasyAD.user_attributes by default credentials: Optionally override the bind credentials json_safe: If true, convert binary data to base64 and datetimes to human-readable strings Returns: Results as a list of dictionaries Raises: ldap.LDAP_ERROR Notes: Setting a small number of search_attributes and return_attributes reduces server load and bandwidth respectively """ if search_attributes is None: search_attributes = EasyAD.user_attributes.copy() if "memberOf" in search_attributes: search_attributes.remove("memberOf") if "thumbnailPhoto" in search_attributes: search_attributes.remove("thumbnailPhoto") if return_attributes is None: return_attributes = EasyAD.user_attributes.copy() generated_attributes = ["disabled", "passwordExpired", "passwordNeverExpires", "smartcardRequired"] for attribute in generated_attributes: if attribute in return_attributes: if "userAccountControl" not in return_attributes: return_attributes.append("userAccountControl") break filter_string = "" for attribute in search_attributes: filter_string += "({0}=*{1}*)".format(attribute, escape_filter_chars(user_string)) filter_string = "(&(objectClass=User)(|{0}))".format(filter_string) results = self.search(base=base, filter_string=filter_string, attributes=return_attributes, credentials=credentials, json_safe=json_safe) results = list(map(lambda user: enhance_user(user, json_safe=json_safe), results)) return results
def get_by_name(self, name, filter=None): # pylint: disable=W0221,W0613 search_filter = ('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) tenants = self.get_all(search_filter) try: return tenants[0] except IndexError: raise exception.TenantNotFound(tenant_id=name)
def get_by_name(self, name, filter=None): # pylint: disable=W0221,W0613 search_filter = ('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) tenants = self.get_all(search_filter) try: return tenants[0] except IndexError: return None
def get_by_service(self, service_id): roles = self.get_all("(service_id=%s)" % ldap_filter.escape_filter_chars(service_id)) try: res = [] for role in roles: res.append(role) return res except IndexError: return None
def _perform_search_dn(self, xivo_ldap, username): username_esc = escape_filter_chars(username) filterstr = '{}={}'.format(self.user_login_attribute, username_esc) dn, _ = xivo_ldap.perform_search(self.user_base_dn, ldap.SCOPE_SUBTREE, filterstr=filterstr, attrlist=['']) if not dn: logger.debug('LDAP : No user DN for user_base dn: %s and filterstr: %s', self.user_base_dn, filterstr) return dn
def get_ldap_lists(l, search_strings, parent_list=None): results = set() known_ldap_resp_ctrls = { SimplePagedResultsControl.controlType: SimplePagedResultsControl, } req_ctrl = SimplePagedResultsControl(True, size=ldap_pagination_size, cookie='') if parent_list: filterstr = search_strings['get_all_sub_lists_filter'] % escape_filter_chars(parent_list) else: filterstr = search_strings['get_all_lists_filter'] while True: msgid = l.search_ext(search_strings['list_search_string'], ldap.SCOPE_SUBTREE, serverctrls=[req_ctrl], attrlist=(search_strings['list_cn_field'], search_strings['list_name_field']), filterstr=filterstr) retries = 0 rdata = None while retries < 5: try: rtype, rdata, rmsgid, serverctrls = l.result3(msgid, timeout=ldap_timeout, resp_ctrl_classes=known_ldap_resp_ctrls) except Exception: logger.exception('Error getting ldap list memberships') retries += 1 else: break # ldap sometimees returns good but does not return rdata if rdata is None: break for (dn, data) in rdata: cn_field = data[search_strings['list_cn_field']][0] name_field = data[search_strings['list_name_field']][0] if isinstance(cn_field, bytes): cn_field = cn_field.decode('utf-8') if isinstance(name_field, bytes): name_field = name_field.decode('utf-8') results |= {(cn_field, name_field)} pctrls = [c for c in serverctrls if c.controlType == SimplePagedResultsControl.controlType] if not pctrls: # Paging not supported logger.debug('LDAP pagination not supported') break cookie = pctrls[0].cookie if not cookie: break req_ctrl.cookie = cookie return results
def changePasswd(self, dn, cur_passwd, newpw): dn = escape_filter_chars(dn) try: # Reference: RFC3062 - LDAP Password Modify Extended Operation self.conn.passwd_s(dn, cur_passwd, newpw) return (True,) except ldap.UNWILLING_TO_PERFORM: return (False, "INCORRECT_OLDPW") except Exception, e: return (False, ldaputils.getExceptionDesc(e))
def changePasswd(self, dn, cur_passwd, newpw): dn = escape_filter_chars(dn) try: # Reference: RFC3062 - LDAP Password Modify Extended Operation self.conn.passwd_s(dn, cur_passwd, newpw) return (True,) except ldap.UNWILLING_TO_PERFORM: return (False, 'INCORRECT_OLDPW') except Exception, e: return (False, ldaputils.getExceptionDesc(e))
def _gen_filter(attrtypes, values, extra=None): filt = '' if attrtypes is None: raise ValueError("Attempting to filter on type that doesn't support filtering!") for attr, value in zip(attrtypes, values): if attr is not None and value is not None: filt += '(%s=%s)' % (attr, ldap_filter.escape_filter_chars(value)) if extra is not None: filt += '{FILT}'.format(FILT=extra) return filt
def test_escape_filter_chars_mode0(self): """ test function escape_filter_chars() with escape_mode=0 """ self.assertEquals( escape_filter_chars(r'foobar'), 'foobar' ) self.assertEquals( escape_filter_chars(r'foo\bar'), r'foo\5cbar' ) self.assertEquals( escape_filter_chars( r'foo\bar', escape_mode=0 ), r'foo\5cbar' )
def get_userdn_by_username(username): lo, po = get_machine_connection() if lo: # get the LDAP DN of the authorized user ldap_dn = lo.searchDn('(&(uid=%s)(objectClass=posixAccount))' % escape_filter_chars(username)) if not ldap_dn: CORE.info('The LDAP DN for user %s could not be found' % (username)) return CORE.info('The LDAP DN for user %s is %s' % (username, ldap_dn)) return ldap_dn[0]
def isValidPrinterObject(self): # check printer on current spoolhost for member in self.info['groupMember']: spoolhosts = '(|' for host in self.info['spoolHost']: spoolhosts += filter_format("(univentionPrinterSpoolHost=%s)", [host]) spoolhosts += ')' test = self.lo.searchDn(filter='(&(objectClass=univentionPrinter)(cn=%s)%s)' % (escape_filter_chars(member), spoolhosts)) if len(test) < 1: raise univention.admin.uexceptions.notValidPrinter(_('%(name)s is not a valid printer on Spoolhost %(host)s.') % {'name': member, 'host': self.info['spoolHost']})
def get_by_service(self, service_id): roles = self.get_all('(service_id=%s)' % ldap_filter.escape_filter_chars(service_id)) try: res = [] for role in roles: res.append(role) return res except IndexError: return None
def remove_udm_adconnection(cls, alias): lo, po, mod = cls.init_udm("office365/ad-connection") udm_objs = mod.lookup(None, lo, filter_s="cn=%s" % escape_filter_chars(alias)) if len(udm_objs) == 1: udm_objs[0].remove() return udm_objs[0].dn else: return False
def check_blacklist_attrs(self): for attr in self.add_blacklist_attrs: val = self.backup_data.get(attr, [None])[0] if val: l_filter = '({0}={1})'.format(attr, escape_filter_chars(val)) res = self.lo.search(l_filter) if res: return argparse.Namespace(value=val, attr=attr, dn=res[0][0]) return None
def validate(self, lo, validate_unlikely_changes=False): super(SchoolComputer, self).validate(lo, validate_unlikely_changes) if self.ip_address: name, ip_address = escape_filter_chars( self.name), escape_filter_chars(self.ip_address) if AnyComputer.get_first_udm_obj( lo, '&(!(cn=%s))(ip=%s)' % (name, ip_address)): self.add_error( 'ip_address', _('The ip address is already taken by another computer. Please change the ip address.' )) if self.mac_address: name, mac_address = escape_filter_chars( self.name), escape_filter_chars(self.mac_address) if AnyComputer.get_first_udm_obj( lo, '&(!(cn=%s))(mac=%s)' % (name, mac_address)): self.add_error( 'mac_address', _('The mac address is already taken by another computer. Please change the mac address.' ))
def test_escape_filter_chars_mode1(self): """ test function escape_filter_chars() with escape_mode=1 """ self.assertEquals( escape_filter_chars( '\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f', escape_mode=1 ), r'\c3\a4\c3\b6\c3\bc\c3\84\c3\96\c3\9c\c3\9f' )
def backend(self, backend): """ @param backend - The backend DB name to show monitoring details for. Show monitoring status for the named backend. """ backend_keys = [ 'readonly', 'entrycachehits', 'entrycachetries', 'entrycachehitratio', 'currententrycachesize', 'maxentrycachesize', 'currententrycachecount', 'maxentrycachecount', 'dncachehits', 'dncachetries', 'dncachehitratio', 'currentdncachesize', 'maxdncachesize', 'currentdncachecount', 'maxdncachecount', 'normalizeddncachetries', 'normalizeddncachehits', 'normalizeddncachemisses', 'normalizeddncachehitratio', 'currentnormalizeddncachesize', 'maxnormalizeddncachesize', 'currentnormalizeddncachecount', ] backend = ldap_filter.escape_filter_chars(backend) dn = "cn=%s,%s" % (backend, DN_LDBM) # How do we handle errors? try: backend_status = self.conn.search_s(dn, ldap.SCOPE_SUBTREE, '(cn=monitor)', backend_keys) except ldap.LDAPError as e: return ('Unable to retrieve backend monitor information: ' + 'error %s' + str(e)) status = {} if len(backend_status) == 1: status['dn'] = backend_status[0].dn for k in backend_keys: status[k] = backend_status[0].getValues(k) else: # Error case? pass return status
def test_escape_filter_chars_mode2(self): """ test function escape_filter_chars() with escape_mode=2 """ self.assertEquals( escape_filter_chars( 'foobar', escape_mode=2 ), r'\66\6f\6f\62\61\72' )
def authenticate(email, password): ldap_server = os.environ['INFRABOX_ACCOUNT_LDAP_URL'] ldap_user = os.environ['INFRABOX_ACCOUNT_LDAP_DN'] ldap_password = os.environ['INFRABOX_ACCOUNT_LDAP_PASSWORD'] ldap_base_dn = os.environ['INFRABOX_ACCOUNT_LDAP_BASE'] search_filter = "(mail=%s)" % escape_filter_chars(str(email)) user_dn = None connect = ldap_conn(ldap_server) try: connect.bind_s(ldap_user, ldap_password) result = connect.search_s(ldap_base_dn, ldap.SCOPE_SUBTREE, search_filter, attrlist=['dn']) for r in result: if r[0]: user_dn = r[0] break except Exception as e: logger.warning("authentication error: %s", e) abort(400, 'Invalid email/password combination') finally: connect.unbind_s() if not user_dn: abort(400, 'Invalid email/password combination') connect = ldap_conn(ldap_server) try: connect.bind_s(user_dn, password) result = connect.search_s(ldap_base_dn, ldap.SCOPE_SUBTREE, search_filter, attrlist=['dn', 'cn', 'displayName']) user = result[0] if not user or not user[0]: abort(400, 'Invalid email/password combination') return { 'cn': user[1]['cn'][0], 'displayName': user[1]['displayName'][0] } except Exception as e: logger.exception(e) abort(400, 'Invalid email/password combination') finally: connect.unbind_s()
def check_authz_search(self, parameters): if not cfg.pam_authz_searches: return # escape all parameters variables = dict((k, escape_filter_chars(v)) for k, v in parameters.items()) variables.update( hostname=escape_filter_chars(socket.gethostname()), fqdn=escape_filter_chars(socket.getfqdn()), dn=variables['userdn'], uid=variables['username']) # go over all authz searches for x in cfg.pam_authz_searches: filter = x.value(variables) logging.debug('trying pam_authz_search "%s"', filter) srch = search.LDAPSearch(self.conn, filter=filter, attributes=('dn', )) try: dn, values = srch.items().next() except StopIteration: logging.error('pam_authz_search "%s" found no matches', filter) raise logging.debug('pam_authz_search found "%s"', dn)
def linkUser(self, secondaryMatchVal: str, linkid: str): """ Links the the target database user with the datasource on the provided value. References the defined secondaryMatchAttribute (when this object was instantiated) for the name of the attribute that should be searched to find the user to link. secondaryMatchVal: the value of the AD secondary match field. linkid: the id that should link the datasource record to the target user. """ searchattr = escape_filter_chars(self._secondaryMatchAttribute) searchval = escape_filter_chars(secondaryMatchVal) linkattr = escape_filter_chars(self._targetLinkAttribute) linkid = escape_filter_chars(linkid) dn = self.getUserInfo(searchattr, searchval)["distinguishedName"][0] modlist = [(ldap.MOD_REPLACE, linkattr, [linkid.encode(self._targetEncoding)])] # TODO: Error Handling self._ld.modify_s(dn, modlist)
def search_objects(module, lo, pos, base='', **kwargs): module = _get_module(module, lo, pos) filter_str = '' for key, value in kwargs.iteritems(): filter_str = '%s=%s' % (key, escape_filter_chars(value)) try: objs = module.lookup(None, lo, filter_str, base=base) except udm_errors.noObject: objs = [] for obj in objs: udm_objects.open(obj) return objs
def get_ldap_list_membership(l, search_strings, list_name): results = set() known_ldap_resp_ctrls = { SimplePagedResultsControl.controlType: SimplePagedResultsControl, } req_ctrl = SimplePagedResultsControl(True, size=ldap_pagination_size, cookie='') while True: msgid = l.search_ext( search_strings['user_search_string'], ldap.SCOPE_SUBTREE, serverctrls=[req_ctrl], attrlist=[search_strings['user_mail_field']], filterstr=search_strings['user_membership_filter'] % escape_filter_chars(list_name)) retries = 0 rdata = None while retries < 5: try: rtype, rdata, rmsgid, serverctrls = l.result3( msgid, timeout=ldap_timeout, resp_ctrl_classes=known_ldap_resp_ctrls) except Exception: logger.exception('Error getting ldap list memberships') retries += 1 else: break # ldap sometimees returns good but does not return rdata if rdata is None: break for data in rdata: member = data[1].get(search_strings['user_mail_field'], [None])[0] if isinstance(member, bytes): member = member.decode('utf-8') results |= {member} pctrls = [ c for c in serverctrls if c.controlType == SimplePagedResultsControl.controlType ] if not pctrls: # Paging not supported logger.debug('LDAP pagination not supported') break cookie = pctrls[0].cookie if not cookie: break req_ctrl.cookie = cookie return results
def get_ldap_lists(l, search_strings, parent_list=None): results = set() known_ldap_resp_ctrls = { SimplePagedResultsControl.controlType: SimplePagedResultsControl, } req_ctrl = SimplePagedResultsControl(True, size=ldap_pagination_size, cookie='') if parent_list: filterstr = search_strings[ 'get_all_sub_lists_filter'] % escape_filter_chars(parent_list) else: filterstr = search_strings['get_all_lists_filter'] while True: msgid = l.search_ext(search_strings['list_search_string'], ldap.SCOPE_SUBTREE, serverctrls=[req_ctrl], attrlist=(search_strings['list_cn_field'], search_strings['list_name_field']), filterstr=filterstr) rtype, rdata, rmsgid, serverctrls = l.result3( msgid, timeout=ldap_timeout, resp_ctrl_classes=known_ldap_resp_ctrls) for (dn, data) in rdata: cn_field = data[search_strings['list_cn_field']][0] name_field = data[search_strings['list_name_field']][0] if isinstance(cn_field, bytes): cn_field = cn_field.decode('utf-8') if isinstance(name_field, bytes): name_field = name_field.decode('utf-8') results |= {(cn_field, name_field)} pctrls = [ c for c in serverctrls if c.controlType == SimplePagedResultsControl.controlType ] if not pctrls: # Paging not supported break cookie = pctrls[0].cookie if not cookie: break req_ctrl.cookie = cookie return results
def get_user(username: str) -> User: found = False ambiguous = False matricolized = matricolize(username) username = escape_filter_chars(username) if matricolized is None: filters = ( f"(&(objectClass=weeeOpenPerson)(uid={username})(!(nsaccountlock=true)))", f"(&(objectClass=weeeOpenPerson)(weeelabnickname={username})(!(nsaccountlock=true)))" ) else: filters = ( f"(&(objectClass=weeeOpenPerson)(schacpersonaluniquecode={matricolized})(!(nsaccountlock=true)))", ) del matricolized try: print(f"Asking {LDAP_SERVER} for info...") conn = ldap.initialize(f"ldap://{LDAP_SERVER}:389") conn.protocol_version = ldap.VERSION3 conn.start_tls_s() conn.simple_bind_s(LDAP_BIND_DN, LDAP_PASSWORD) except ldap.SERVER_DOWN: print(f"Cannot connect to LDAP server {LDAP_SERVER}") secure_exit(38) # noinspection PyTypeChecker return None # Stops complaints from the IDE if conn is None: print(f"{PROGRAM_NAME}: Error connecting to LDAP server :(") secure_exit(38) for the_filter in filters: result = conn.search_s(LDAP_TREE, ldap.SCOPE_SUBTREE, the_filter, ('uid', 'cn', 'givenname')) if len(result) > 1: ambiguous = True if len(result) == 1: attr = result[0][1] return User(attr['uid'][0].decode(), attr['cn'][0].decode(), attr['givenname'][0].decode()) conn.unbind_s() if ambiguous: print( f"{PROGRAM_NAME}: Multiple accounts found for that username/matricola/nickname, try with another one." ) secure_exit(2) if not found: print( f"{PROGRAM_NAME}: Username not recognized. Maybe you misspelled it or you're an intruder." ) secure_exit(2)
def check_authzsearch(self, parameters): if not cfg.pam_authz_searches: return # escape all parameters variables = dict((k, escape_filter_chars(v)) for k, v in parameters.items()) variables.update( hostname=escape_filter_chars(socket.gethostname()), fqdn=escape_filter_chars(socket.getfqdn()), dn=variables['userdn'], uid=variables['username'], ) # go over all authz searches for x in cfg.pam_authz_searches: filter = x.value(variables) logging.debug('trying pam_authz_search "%s"', filter) srch = search.LDAPSearch(self.conn, filter=filter, attributes=('dn', )) try: dn, values = srch.items().next() except StopIteration: logging.error('pam_authz_search "%s" found no matches', filter) raise logging.debug('pam_authz_search found "%s"', dn)
def check_group_membership(username, group=None): with initialize_connection() as connection: connection.simple_bind_s(config.LDAP_BIND_DN, config.LDAP_BIND_PASSWORD) if group is None: query = config.LDAP_GROUP_ALL else: query = config.LDAP_GROUP_OBJECT_FILTER % {'group': ldap_filter.escape_filter_chars(group)} results = connection.search_s(config.LDAP_GROUP_BASE_DN, ldap.SCOPE_SUBTREE, query) members = itertools.chain.from_iterable([result[1]['memberUid']for result in results]) encoding = config.LDAP_ENCODING members = [member.decode(encoding) for member in members] is_member = username in members return is_member
def ingroup(request, mail, cn): # first, figure out the uid mail_filter = make_search_filter(dict(mail=mail)) alias_filter = make_search_filter(dict(emailAlias=mail)) search_filter = '(|{}{})'.format(mail_filter, alias_filter) rs = connection().search_s(settings.LDAP_SEARCH_BASE, ldap.SCOPE_SUBTREE, search_filter, ['uid']) uid = None for dn, result in rs: uid = result['uid'][0] break if not uid: return False search_filter = u""" (| (&(objectClass=groupOfNames)(cn=%(groupname)s)(member=%(dn)s)) (&(objectClass=posixGroup)(|(cn=scm_*)(cn=svn_*))(cn=%(groupname)s)(memberUid=%(mail)s)) (&(objectClass=posixGroup)(!(|(cn=scm_*)(cn=svn_*)))(cn=%(groupname)s)(memberUid=%(uid)s)) ) """ search_filter = search_filter % { 'groupname': escape_filter_chars(cn), 'dn': escape_filter_chars(dn), 'uid': escape_filter_chars(uid), 'mail': escape_filter_chars(mail), } search_filter = search_filter.strip() rs = connection().search_s(settings.GROUP_LDAP_SEARCH_BASE, ldap.SCOPE_SUBTREE, search_filter, ['cn']) for __ in rs: return True return False
def get_group(self, group_string, base=None, credentials=None, attributes=None, json_safe=False): """ Searches for a unique group object and returns its attributes Args: group_string: A group name, cn, or dn base: Optionally override the base object dn credentials: A optional dictionary of the username and password to use. If credentials are not passed, the credentials from the initial EasyAD configuration are used. attributes: An optional list of attributes to return. Otherwise uses self.group_attributes. To return all attributes, pass an empty list. json_safe: If true, convert binary data to base64 and datetimes to human-readable strings Returns: A dictionary of group attributes Raises: ValueError: Query returned no or multiple results ldap.LDAP_ERROR: An LDAP error occurred """ if base is None: base = self.config["AD_BASE_DN"] if attributes is None: attributes = self.group_attributes.copy() group_filter = "(&(objectClass=Group)(|(cn={0})(distinguishedName={0})))".format( escape_filter_chars(group_string)) results = self.search(base=base, filter_string=group_filter, credentials=credentials, attributes=attributes, json_safe=json_safe) if len(results) == 0: raise ValueError("No such group") elif len(results) > 1: raise ValueError("The query returned more than one result") group = results[0] if "member" in group.keys(): group["member"] = sorted(group["member"], key=lambda dn: dn.lower()) return group
def search_for_groups(self, group_string, base=None, search_attributes=None, return_attributes=None, credentials=None, json_safe=False): """ Returns matching group objects as a list of dictionaries Args: group_string: The substring to search for base: Optionally override the base object's DN search_attributes: The attributes to search through, with binary data removed easyad.EasyAD.group_attributes by default return_attributes: A list of attributes to return. easyad.EasyAD.group_attributes by default credentials: Optionally override the bind credentials json_safe: If true, convert binary data to base64 and datetimes to human-readable strings Returns: Results as a list of dictionaries Raises: ldap.LDAP_ERROR Notes: Setting a small number of search_attributes and return_attributes reduces server load and bandwidth respectively """ if search_attributes is None: search_attributes = EasyAD.group_attributes.copy() if "member" in search_attributes: search_attributes.remove("member") if return_attributes is None: return_attributes = EasyAD.group_attributes.copy() filter_string = "" for attribute in search_attributes: filter_string += "({0}=*{1}*)".format( attribute, escape_filter_chars(group_string)) filter_string = "(&(objectClass=Group)(|{0}))".format(filter_string) results = self.search(base=base, filter_string=filter_string, attributes=return_attributes, credentials=credentials, json_safe=json_safe) return results
def user_to_dn(self, username, ldap_config): user_dn = None user_id = None user_mail = None try: conn = self.get_connection(ldap_config) LOG.debug("Connection obtained to try and map user %s to dn" % username) if ldap_config.user is not None: LOG.debug("Binding being requested for user: %s" % ldap_config.user) conn.simple_bind_s(ldap_config.user, ldap_config.password) LOG.debug("Binding obtained") query = ('(&(%(name_attr)s=%(name)s)' '%(filter)s' '(objectClass=%(object_class)s))' % { 'name_attr': ldap_config.user_name_attribute, 'name': ldap_filter.escape_filter_chars(username), 'filter': (ldap_config.user_filter or ''), 'object_class': ldap_config.user_objectclass }) # Build the attribute list...we always want the dn... attrlist = ['dn'] # ...plus additionally a specific attribute for the user_id and email if ldap_config.user_id_attribute != 'dn': attrlist.append(ldap_config.user_id_attribute) if ldap_config.user_mail_attribute is not None: attrlist.append(ldap_config.user_mail_attribute) users = conn.search_s(ldap_config.user_tree_dn, ldap.SCOPE_SUBTREE, query, attrlist) for dn, attrs in users: user_dn = dn if ldap_config.user_id_attribute == 'dn': user_id = dn else: value = attrs[ldap_config.user_id_attribute] if (isinstance(value, list)): user_id = value[0] else: user_id = value value = attrs.get(ldap_config.user_mail_attribute, None) if (isinstance(value, list)): user_mail = value[0] else: user_mail = value break except Exception, e: LOG.debug("Ldap user to dn failed due to: " + str(e))
def search_objects(_module, _lo, _pos, _base='', **kwargs): module = _get_module(_module, _lo, _pos) expressions = [] conj = udm_filter.conjunction('&', expressions) for key, value in kwargs.iteritems(): expressions.append( udm_filter.expression(key, escape_filter_chars(value), '=')) try: objs = module.lookup(None, _lo, str(conj), base=_base) except udm_errors.noObject: objs = [] for obj in objs: udm_objects.open(obj) return objs
def get_user(self, username): username = ldap_filter.escape_filter_chars(username) dn = f"uid={username},cn=users,cn=accounts,{self.basedn}" filters = "(objectClass=person)" scope = ldap.SCOPE_BASE # attrlist = ["*", "+"] attrlist = list(c.attrname for c in USER_ATTR) result = self.conn.search_s(dn, scope, filters, attrlist) if not result: return None attrs = result[0][1] result = {c.destname: c(attrs) for c in USER_ATTR} # result['raw'] = repr(attrs) return result
def is_valid_printer_object(self): # check printer on current spoolhost spoolhosts = '(|%s)' % ''.join( filter_format('(univentionPrinterSpoolHost=%s)', [host]) for host in self.info['spoolHost']) for member in self.info['groupMember']: if not self.lo.searchDn( filter='(&(objectClass=univentionPrinter)(cn=%s)%s)' % (escape_filter_chars(member), spoolhosts)): raise univention.admin.uexceptions.notValidPrinter( _('%(name)s is not a valid printer on Spoolhost %(host)s.') % { 'name': member, 'host': self.info['spoolHost'] })
def wait_for_drs_replication_of_membership(self, group_dn, member_uid, is_member=True, try_resync=True, **kwargs): """ wait_for_drs_replication() of a user to become a member of a group. :param group: str: DN of a group :param member_uid: str: username :param is_member: bool: whether the user should be a member or not :param try_resync: bool: if waiting for drs replication didn't succeed, run "/usr/share/univention-s4-connector/resync_object_from_ucs.py <group_dn>" and wait again :param kwargs: dict: will be passed to wait_for_drs_replication() with a modified 'ldap_filter' :return: None | <ldb result> """ try: user_filter = kwargs['ldap_filter'] if user_filter and not user_filter.startswith('('): user_filter = '({})'.format(user_filter) except KeyError: user_filter = '' if is_member: member_filter = '(memberOf={})'.format(escape_filter_chars(group_dn)) else: member_filter = '(!(memberOf={}))'.format(escape_filter_chars(group_dn)) kwargs['ldap_filter'] = '(&(cn={}){}{})'.format( escape_filter_chars(member_uid), member_filter, user_filter ) res = wait_for_drs_replication(**kwargs) if not res: self.log.warn('No result from wait_for_drs_replication().') if try_resync: cmd = ['/usr/share/univention-s4-connector/resync_object_from_ucs.py', group_dn] self.log.info('Running subprocess.call(%r)...', cmd) subprocess.call(cmd) self.log.info('Waiting again. Executing: wait_for_drs_replication_of_membership(group_dn=%r, member_uid=%r, is_member=%r, try_resync=False, **kwargs=%r)...', group_dn, member_uid, is_member, kwargs) # recursion once with try_resync=False res = self.wait_for_drs_replication_of_membership(group_dn=group_dn, member_uid=member_uid, is_member=is_member, try_resync=False, **kwargs) return res
def get_share_fileserver_dn(self, set_by_self, lo): if set_by_self: set_by_self = self.get_name_from_dn(set_by_self) or set_by_self hostname = set_by_self or self.get_dc_name() if hostname == self.get_dc_name_fallback(): # does not matter if exists or not - dc object will be created later host = SchoolDC(name=hostname, school=self.name) return host.dn host = AnyComputer.get_first_udm_obj(lo, 'cn=%s' % escape_filter_chars(hostname)) if host: return host.dn else: logger.warning('Could not find %s. Using this host as ShareFileServer ("%s").', hostname, ucr.get('hostname')) return ucr.get('ldap/hostdn')
def user_to_dn(self, username, ldap_config): user_dn = None user_id = None user_mail = None try: conn = self.get_connection(ldap_config) LOG.debug("Connection obtained to try and map user %s to dn" % username) if ldap_config.user is not None: LOG.debug("Binding being requested for user: %s" % ldap_config.user) conn.simple_bind_s(ldap_config.user, ldap_config.password) LOG.debug("Binding obtained") query = ('(&(%(name_attr)s=%(name)s)' '%(filter)s' '(objectClass=%(object_class)s))' % {'name_attr': ldap_config.user_name_attribute, 'name': ldap_filter.escape_filter_chars(username), 'filter': (ldap_config.user_filter or ''), 'object_class': ldap_config.user_objectclass}) # Build the attribute list...we always want the dn... attrlist = ['dn'] # ...plus additionally a specific attribute for the user_id and email if ldap_config.user_id_attribute != 'dn': attrlist.append(ldap_config.user_id_attribute) if ldap_config.user_mail_attribute is not None: attrlist.append(ldap_config.user_mail_attribute) users = conn.search_s(ldap_config.user_tree_dn, ldap.SCOPE_SUBTREE, query, attrlist) for dn, attrs in users: user_dn = dn if ldap_config.user_id_attribute == 'dn': user_id = dn else: value = attrs[ldap_config.user_id_attribute] if (isinstance(value, list)): user_id = value[0] else: user_id = value value = attrs.get(ldap_config.user_mail_attribute, None) if (isinstance(value, list)): user_mail = value[0] else: user_mail = value break except Exception, e: LOG.debug("Ldap user to dn failed due to: " + str(e))
def deleteObjWithDN(self, domain, dn, account, accountType): self.domain = web.safestr(domain) if not iredutils.is_domain(self.domain): return (False, "INVALID_DOMAIN_NAME") self.dn = escape_filter_chars(dn) # Used for logger. self.account = web.safestr(account) try: deltree.DelTree(self.conn, self.dn, ldap.SCOPE_SUBTREE) web.logger(msg="Delete %s: %s." % (str(accountType), self.account), domain=self.domain, event="delete") return (True,) except Exception, e: return (False, ldaputils.getExceptionDesc(e))
def __init__(self, uri, auth_user, auth_password, base_dn, group=None): """ Constructs and binds an LDAPKeyProvider instance to the server identified by the uri using auth_user and auth_password for authentication. When users are looked up, it is verified that they belong to the provided group. """ self.group = None if group: self.group = filter.escape_filter_chars(group) self.base_dn = base_dn # I know, this is not functionality the ldap module straightforwardly # exposes, but it seems to work. self.conn = ldap.ldapobject.ReconnectLDAPObject(uri) self.conn.simple_bind(auth_user, auth_password)
def _make_ldap_query(self, query_args, unique=True): """ Execute an LDAP query for a user who matches the filter parameters provided in the `query_args` dict, where each key is the name of a valid LDAP field, and each value is the value requested for that field. The results of this query will be returned as dict whose keys will match those defined in the `desired_attributes` class attribute. If the `unique` keyword argument is True and more than one record is returned, an error will be raised. """ # Build our filter string filters = "".join([ "(%s=%s)" % (key, escape_filter_chars(val)) for key, val in query_args.iteritems() ]) if len(query_args) > 1: filters = "(&%s)" % filters # The LDAP results object is of the form [0 => user DN, 1 => user info] results = self._ldap_conn.search_st(ldap_settings['LDAP_SEARCH_BASE'], ldap_settings['LDAP_SCOPE'], filters) if results: if unique and len(results) > 1: raise ValueError(_("expected a unique record, but %(record_count)d records were found!") % { 'record_count': len(user_info) }) # Map the LDAP values to our requested attributes info_list = [] for result in [result[1] for result in results]: user_info = {} for dict_key, ldap_val in self.desired_attributes.iteritems(): user_val = result.get(ldap_val) try: user_val = user_val.pop() except AttributeError: pass user_info[dict_key] = user_val user_info['professor'] = user_info.get('professor', [""]) == "Faculty" info_list.append(user_info) return info_list.pop() if unique else info_list return None