LDAP query not working - python

I'm really running out of ideas.
I recently was assigned to improve a script we have in Python so that it can fetch all users whose email match a string (more exactly, all the users whose email match with the value obtained from a HTML's text input).
It works well by using this filter ("search" is the text obtained from the text input):
user_filter = '(mail=%s)' % search
but it needs for the email value to be exactly so it can match with the user's email, and what I need is to match any written down value(string).
The last filter I used was this:
user_filter = '(mail=*%s*)' % search
and also like this:
user_filter = '(mail=%s*)' % search
(please notice the use of wildcards)
but none of them worked.
Any ideas who can I achieve this? Do you need more context?
I'm using ldap and function search_s
This is a snippet of the code:
def ldap_query(query):
""" returns the members of an LDAP group """
try:
ldap_conn = ldap.initialize(LDAP_URL)
ldap_conn.timeout = LDAP_TIMEOUT
ldap_conn.simple_bind(LDAP_USERNAME, LDAP_PASSWORD)
if not ldap_conn.whoami_s():
raise Exception('503 Unable to authenticate to LDAP server with master user & password')
res = ldap_conn.search_s(LDAP_BASE_DN, ldap.SCOPE_SUBTREE, query)
if res == []:
raise Exception('Group not found in LDAP directory, using filter {}'.format(query))
print res
And I'm using it like this:
print ldap_query('(mail=my.name#mycompany.com)')
but if I use the wildcards, I ended up with the error:
print ldap_query('(mail=a.name*)')
EDITED
just now it started to work, by using the last filter (the one just above here). Dunno why it didn't work before.

It worked well by using just one wildcard:
'(mail=a.name*)
rather than two:
'(mail=*a.name*)
I used that approach because of what I've seen while working with MysQL "LIKE" query %string%, whereas with LDAP filters seems not to be the case.

Related

Check if username already exists in database (Python + Pymongo)

I'm trying to make a registration module to use in a larger login/authentication program and I need to make a function that can check if a username already exists in a collection.
I haven't tried much more than this, this is my first real programming project and I'm stuck on this part. I realize I could use in-line dictionary databases, but I want to learn how to integrate 3rd party databases with my programming.
from pymongo import MongoClient
import time
client = MongoClient('localhost', 27017)
loginDB = client["loginDB"]
userCol = loginDB["userCol"]
##Username##
print('Choose A Unique Username')
time.sleep(1.2)
unameInput = input("Enter Username: ")
unameList = {'Username': unameInput}
unameQuery = {}
unameQuery2 = userCol.find_one({'Username.Username': {'$gt': 'a'}})
if unameInput != unameQuery2:
print('Name is Available | Accepted!')
allList = {'Username': unameList}
userCol.insert_one(allList)
else:
print('Sorry, Please Try Again.')`
The expected result is to search the database for everything that starts with the letter "a", forward. If the input (unameInput) does not equal anything in the query result (unameQuery2), then print "Username is available". If anything in the query matches the input, then print "Please try again", however, it's accepting everything that is input and exiting the code.
You are using find_one() to find one entry in Username and then checking if unameInput is equal to it. If it's not an exact match, it will execute the code for name is available.
Try find() instead as this will iterate over all the documents in the collection.
unameQuery2 = userCol.find()
if unameInput not in unameQuery2:
# do something
I figured it out, I was putting dictionaries inside of dictionaries inside of documents, as well as not iterating "allList".

LDAP Query Filter User's with Groups Like *x*

I'm currently using Python and LDAP to query Active Directory for users.
I have a list of names that are First Last. Not specific enough to find the exact user.
I would like a filter that would find all users matching 'Last, First*'
and belonging to any group with a keyword in it.
_filter = '''(& (objectclass=user)
(objectcategory=person)
(name={}*) )'''.format(search_string)
and I've tried adding...
(memberOf=CN=*Keyword*,OU=Delegated,OU=Groups,DC=amr,DC=corp,DC=xxxxxx,DC=com)
To my filter, but with no success.
If this was SQL, I would write something like:
Select *
From
Users
Where
Users.name like 'First, Last%'
and Users.memberOf like 'Keyword%'
Update:
After reviewing Gabriel's answer I'm running this.
def get_idsids(self, search_string):
_filter = '''(& (objectclass=user)
(objectcategory=person)
(anr={}) )'''.format(search_string)
# Search for user.
# Will return list of users matching criteria.
# The results are wrapped up as a list(tuple(dict))) where the dict vals are binary strings or lists of binary strings.
users = self.con.search_s(ActiveDirUser.BASEDN, ldap.SCOPE_SUBTREE, _filter, ['displayName', 'sAMAccountName', 'memberOf'])
# This line is ugly... It just converts the results to a list of ids
# So long as the user has at least one group with 'Keyword' in the name.
# upper() is used to make the Keyword requriement case insensitive.
return [user[1]['sAMAccountName'][0].decode() for user in users if 'KEYWORD' in ''.join(map(str, user[1]['memberOf'])).upper()]
I do wonder though, could I search for groups with 'Keyword' in the name and build filters from that? Further, would that be faster? I assume it would as AD probably hashes group membership.
I will go do some reading, but I assume group names are wildcard searchable?
I suggest you use Ambiguous Name Resolution:
_filter = '''(& (objectclass=user)
(objectcategory=person)
(anr={}) )'''.format(search_string)
Read that documentation to understand how it works, but it can find users if you give it a string of "first last". This is what the search box in AD Users and Computers uses.
Just be aware that you can get doubles if people have similar names. If you take my name for example: if you would search for "Gabriel Luci", and there was someone else with the name "Gabriel Luciano", you would find both of us.
This:
(memberOf=CN=*Keyword*,OU=Delegated,OU=Groups,DC=amr,DC=corp,DC=xxxxxx,DC=com)
doesn't work because you can't use wildcards on any attribute that is a distinguishedName, like memberOf.
That's for Active Directory anyway. Other LDAP directories might allow it.
If you need to check if the users are members of groups, then you can tell your search to return the memberOf attribute in the search (I don't know phython, but you should have a way of telling it which attributes you want returned). Then you can loop through the groups in the memberOf attribute and look for that keyword.

django-mongodb-engine can't update an object

I am writing a Django-based back end using django-mongodb-engine for an android app and I'm trying to get data from a PUT request to update a record in my database. I'm getting a username and filtering the database for the user object with that name (successfully), but the save function doesn't seem to be saving the changes. I can tell the changes aren't being saved because when I go onto mLab's online database management tool the changes aren't there.
Here's the code:
existing_user = User.objects.filter(userName = user_name)
if existing_user == None:
response_string += "<error>User not identified: </error>"
elif (existing_user[0].password != user_pwd):
response_string += "<error>Password error.</error>"
#if we have a validated user, then manipulate user data
else:
existing_user[0].star_list.append(new_star)
existing_user[0].save()
I'm not getting any error messages, but the data remains the same. The star_list remains empty after the above. In fact, as a test I even tried replacing the else clause above with:
else:
existing_user[0].userName = "Barney"
existing_user[0].save()
And following this call, the existing_user[0].userName is still it's original value ("Fred", rather than "Barney")!
Found an answer to this question. I'm not sure why it wasn't working as posted, but there were problems trying to access the object through the list... in other words the following didn't work:
existing_user[0].userName = "Barney"
existing_user[0].save()
But this did:
found_user = existing_user[0]
found_user.userName = "Barney"
found_user.save()
Based on my understanding of Python lists, either one should be the same... but maybe some python genius out there can explain why they aren't?

Validate email local component

I'm writing a registration form that only needs to accept the local component of a desired email address. The domain component is fixed to the site. I am attempting to validate it by selectively copying from validators.validate_email which Django provides for EmailField:
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
# quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"'
r')#((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$)' # domain
r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
Following is my code. My main issue is that I'm unable to adapt the regex. At this point I'm only testing it in a regex tester at http://www.pythonregex.com/ however it's failing:
^([-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*)$
This seems to be passing undesirable characters such as ?
The entire code for my Field, which is not necessarily relevant at this stage but I wouldn't mind some comment on it would be:
class LocalEmailField(CharField):
email_local_re = re.compile(r"^([-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*)$", re.IGNORECASE)
validate_email_local = RegexValidator(email_re, (u'Enter a valid e-mail username.'), 'invalid')
default_validators = [validate_email_local]
EDIT: To clarify, the user is only entering the text BEFORE the #, hence why I have no need to validate the #domain.com in the validator.
EDIT 2: So the form field and label will look like this:
Desired Email Address: [---type-able area---] #domain.com
You say "undesirable characters such as ?", but I think you're mistaken about what characters are desirable. The original regex allows question marks.
Note that you can also define your own validator that doesn't use a massive regex, and have some chance of decoding the logic later.
Some people, when confronted with a problem, think, “I know, I’ll use
regular expressions.” Now they have two problems. - Jamie
Zawinski
Checking via regex is an exercise in wasting your time. The best way is to attempt delivery; this way not only can you verify the email address, but also if the mailbox is actually active and can receive emails.
Otherwise you'll end up in an every-expanding regular expression that can't possibly hope to match all the rules.
"Haha boo hoo woo woo!"#foo.com is a valid address, so is qwerterukeriouo#gmail.com
Instead, offer the almost-standard "Please click on the link in the email we sent to blahblah#goo.com to verify your address." approach.
If you want to create email addresses, then you can write your own rules on what can be a part of the email component; and they can be a subset of the official allowed chars in the RFC.
For example, a conservative rule (that doesn't use regular expressions):
allowed_chars = [string.digits+string.letters+'-']
if len([x in user_input if x not in allowed_chars]):
print 'Sorry, invalid characters'
else:
if user_input[0] in string.digits+'-':
print 'Cannot start with a number or `-`'
else:
if check_if_already_exists(user_input):
print 'Sorry, already taken'
else:
print 'Congratulations!'
I'm still new to Django and Python, but why reinvent the wheel and maintain your own regex? If, apart from wanting users to enter only the local portion of their email address, you're happy with Django's built-in EmailField, you can subclass it quite easily and tweak the validation logic a bit:
DOMAIN_NAME = u'foo.com'
class LocalEmailField(models.EmailField):
def clean(local_part):
whole_address = '%s#%s' % (local_part, DOMAIN_NAME)
clean_address = super(LocalEmailField, self).clean(whole_address)
# Can do more checking here if necessary
clean_local, at_sign, clean_domain = clean_address.rpartition('#')
return clean_local
Have you looked at the documentation for Form and Field Validation and the .clean() method?
If you want to do it 100% correctly with regex, you need to use an engine with some form of extended regex which allow matching nested parentheses.
Python's default engine does not allow this, so you're better off compromising with a very simple (permissive) regex.

How to implement Django like 'contains' filter query with Google App Engine?

Is there some way to implement Django like contains or icontains filters with Google App Engine as well? I am using app engine patch.
I have used the below query earlier to match the start of a string but now the requirement is to find a string pattern within Datastore.
Employee.all().filter('name >=',value).filter('name <',unicode(value) + u'\ufffd')
Basically the requirement is to implement a search functionality with all the strings containing the search string as a result.
Please suggest.
Thanks in advance.
What you need to do is create a string list property with the different string permutations and query on that list.
Take a look at appengine.ext.search.SearchableModel for an example implementation.
You can also check out nonrel-search.
No, a true substring search isn't really possible in the datastore.
The best you could do would be to add a keyword index and do the "begins with" type query from your question on that, but even then for an entity like "foo bar baz" you could match when searching for "ba" but not "ar b".
This sounds like a great job for BigQuery, which is in preview right now with a wait list to get access.
Recently I ran into the same problem and made my own model manager with an overriden filter function that also understands __contains. I'm assuming you're using Django.
class UserFeedManager(models.Manager):
def filter(self, *args, **kwargs):
keywordargs = {}
for (arg, val) in kwargs.items():
if '__contains' in arg:
contains.append((arg.split('__')[0], val))
else:
keywordargs[arg] = val
result = []
if len(contains) > 0:
for entry in super(UserFeedManager, self).filter(*args, **keywordargs):
if all(map(lambda (attr, val): val in entry.__getattribute__(attr),
contains)):
result.append(entry)
else:
result = super(UserFeedManager, self).filter(*args, **keywordargs)
return result
Essentially it builds a list of arguments that have a __contains, then fetches the whole result and filters it to only hold the results that pass all criteria.
querySet = Entity.objects.all()
ids = []
for i,obj in enumerate(querySet.iterator()):
str_to_search =obj.name
if str_to_search.find('blahblah') != -1:
ids.append(obj.id)
querySet = querySet.filter(id__in = ids)

Categories