LDAP search with username as variable - python

I am using the Python-LDAP module and trying to make a query on the logged in user. The username will be passed into the query. When I simply type the username in as a string my results come out correctly.
But if I try to pass the (username) variable it returns
LDAPError - FILTER_ERROR: {'desc': u'Bad search filter'} I've tried a number of different combinations but continue to get the same error returned. Any insight here would be great!
Edited for Minimal, Complete, and Verifiable example:
import ldap
LDAP_SERVER = "ldap://myldapserver.domain.ad:389"
username = r"domain\serviceAccount"
password = "Password"
l = ldap.initialize(LDAP_SERVER)
def login(username, password):
try:
l.simple_bind_s(username, password)
base = "OU=Users,OU=Group,DC=domain,DC=ad"
criteria = "(&(objectClass=user)(sAMAccountName=anActualUsername))" #WORKS
criteria = '(&(objectClass=user)(sAMAccountName=%s))' % username #DOESNT WORK
criteria = "(&(objectClass=user)" + "(sAMAccountName=" + username + "))" #DOESNT WORK
attributes = ['displayName']
result = l.search_s(base, ldap.SCOPE_SUBTREE, criteria, attributes)
print result
except ldap.INVALID_CREDENTIALS:
return False
return True
login(username,password)

Did you try to encode your string ?
criteria = ('(&(objectClass=user)(sAMAccountName=%s))' % username).encode('utf8')

In the "WORKS" case, your filter string contains a simple name with no domain:
(&(objectClass=user)(sAMAccountName=bobsmith))
In the "DOESN'T WORK" case, you use a name with a domain:
(&(objectClass=user)(sAMAccountName=domain\serviceAccount)
The character \ is not allowed in a filter string unless it is escaped.
How to fix this depends upon the data present in your ldap server. Perhaps this:
criteria = '(&(objectClass=user)(sAMAccountName=%s))' % (
username if '\\' not in username else username.split('\\')[1])
Or perhaps this:
criteria = '(&(objectClass=user)(sAMAccountName=%s))' % (
ldap.filter.escape_filter_chars(username))

I needed to use ldap.filter.filter_format for proper character escaping.
import ldap.filter
criteria= ldap.filter.filter_format('(&(objectClass=user)(sAMAccountName=%s))', [username])

Try switching single quotes with double quotes.
criteria = "(&(objectClass=user)(sAMAccountName=anActualUsername))" #WORKS
criteria = '(&(objectClass=user)(sAMAccountName=%s))' % username #DOESNT WORK
the second criteria change it to this one (I didn't try with %s but only string):
criteria = "(&(objectClass=user)(sAMAccountName=%s))" % username #SHOULD WORK

Related

Is there an equivalent to RStudio's ".rs.askForPassword" in Python?

I want to connect to my database in Python, but i don't want to show my password to other users, like .rs.askForPassword does exactly what i need in RStudio. Here's an example:
library(RODBC)
conn = odbcConnect(dsn = "my_dsn",
uid = "name.last_name",
pwd = .rs.askForPassword("my.password"))
Is there any way to do this in Python?
You may use getpass()
import getpass
p = getpass.getpass(prompt='What is your favorite person? ')
if p.lower() == 'gf':
print 'Right. Off you go.'
else:
print 'Wrong!'

python-ldap unable to do any basic search queries on open server

I have been trying to do some basic search queries, but I am unable to connect to an open LDAP server regardless. I tried a couple of servers, and none of them worked. I used Apache Directory Studio to make sure that the keyword was there but it did not work either way. I tried a variety of different code from different sources.
This was the first one I used
:
https://www.linuxjournal.com/article/6988
import ldap
keyword = "boyle"
def main():
server = "ldap.forumsys.com"
username = "cn=read-only-admin,dc=example,dc=com"
password = "password"
try:
l = ldap.open(server)
l.simple_bind_s(username,password)
print "Bound to server . . . "
l.protocol_version = ldap.VERSION3
print "Searching . . ."
mysearch (l,keyword)
except ldap.LDAPError:
print "Couldnt connect"
def mysearch(l, keyword):
base = ""
scope = ldap.SCOPE_SUBTREE
filter = "cn=" + "*" + keyword + "*"
retrieve_attributes = None
count = 0
result_set = []
timeout = 0
try:
result_id = l.search(base, scope, filter, retrieve_attributes)
while l != 1:
result_id = l.search(base, scope,filter, retrieve_attributes)
result_type, result_data = l.result(result_id, timeout)
if result_data == []:
break
else:
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
if len (result_set = 0):
print "No Results"
for i in range (len(result_set)):
for entry in result_set[i]:
try:
name = entry[1]['cn'][0]
mail = entry[1]['mail'][0]
#phone = entry[1]['telephonenumber'][0]
#desc = entry[1]['description'][0]
count = count + 1
print name + mail
except:
pass
except ldap.LDAPError, error_message:
print error_message
main()
Every time I ran this program, I received an error
{'desc': u"No such object"}
I also tried this
import ldap
try:
l = ldap.open("ldap.example.com")
except ldap.LDAPError, e:
print e
base_dn = "cn=read-only-admin,dc=example,dc=com"
search_scope = ldap.SCOPE_SUBTREE
retrieve_attributes = None
search_filter = "uid=myuid"
try:
l_search = l.search(base_dn, search_scope, search_filter, retrieve_attributes)
result_status, result_data = l.result(l_search, 0)
print result_data
except ldap.LDAPError, e:
print e
The error on this one was
{'desc': u"Can't contact LDAP server"}
I spent about 5 hours trying to figure this out. I would really appreciate it if you guys could give me some advice. Thanks.
There are several bogus things in there.
I will only comment your first code sample because it can be used by anyone with that public LDAP server.
l = ldap.open(server)
Function ldap.open() is deprecated since many years. You should use function ldap.initialize() with LDAP URI as argument instead like this:
l = ldap.initialize("ldap://ldap.forumsys.com")
l_search = l.search(..)
This is the asynchronous method which just returns a message ID (int) of the underlying OpenLDAP C API (libldap). It's needed if you want to retrieve extended controls returned by the LDAP server along with search results. Is that what you want?
As a beginner you probably want to use the simpler method LDAPObject.search_s() which immediately returns a list of (DN, entry) 2-tuples.
See also: python-ldap -- Sending LDAP requests
while l != 1
This does not make sense at all because l is your LDAPObject instance (LDAP connection object). Note that LDAPObject.search() would raise an exception if it gets an Integer error code from OpenLDAP's libldap. No need to do C-style error checks at this level.
filter = "cn=" + "" + keyword + ""
If keyword can be arbitrary input this is a prone to LDAP injection attacks. Don't do that.
For adding arbitrary input into a LDAP filter use function ldap.filter.escape_filter_chars() to properly escape special characters. Also avoid using variable name filter because it's the name of a built-in Python function and properly enclose the filter in parentheses.
Better example:
ldap_filter = "(cn=*%s*)" % (ldap.filter.escape_filter_chars(keyword))
base = ""
The correct search base you have to use is:
base = "dc=example,dc=com"
Otherwise ldap.NO_SUCH_OBJECT is raised.
So here's a complete example:
import pprint
import ldap
from ldap.filter import escape_filter_chars
BINDDN = "cn=read-only-admin,dc=example,dc=com"
BINDPW = "password"
KEYWORD = "boyle"
ldap_conn = ldap.initialize("ldap://ldap.forumsys.com")
ldap_conn.simple_bind_s(BINDDN, BINDPW)
ldap_filter = "(cn=*%s*)" % (ldap.filter.escape_filter_chars(KEYWORD))
ldap_results = ldap_conn.search_s(
"dc=example,dc=com",
ldap.SCOPE_SUBTREE,
ldap_filter,
)
pprint.pprint(ldap_results)

Finding a recurrance of three ASCII families in a string

I'm trying to create a 'check' system for a password generator that will advsie whether or not three of the same types of character family are found in a row in a generated password, i.e
If the password is
y8kpBD8zcZLKRSh1j7vwCMDQ5orR8VEP
it will find 'ZLK' etc
I first thought lowercase_repeat = re.compile("[a-z]{3}") would for example find three lowercase repeats, but I can't seem to understand how this works exactly.
The password generator is below:
import random
import re
generator = random.SystemRandom()
password_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!##$%^&*()'
password = ''.join(generator.choice(password_characters) for _ in range(32))
print password
If you just want to check for specific character sets; e.g: all uppercase, all lowercase, digit and non-alnum - you can create a non-capturing group for each set. For example:
import re
pattern = '(?:[a-z]{3}|[A-Z]{3}|\d{3}|[\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]{3})'
password = 'y8kpBD8zcZLKRSh1j7vwCMDQ5orR8VEP!'
matches = re.search(pattern, password)
The variable matches returns None if there are no matches, indicating the password passes.
The pattern [\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E] is a (probably pretty gnarly) way to catch a set of all non-alnum ascii characters (hex codes). It represents the following set:
[space] ! " # $ % & ' ( ) * + , - . / : ; < = > ? # [ \ ] ^ _ ` { | } ~
I pulled it out of an old project, so YMMV. I'm sure there might be a more succinct way to express it - indeed, you might prefer to explicitly specify a set; e.g: [!?#] etc.
Quick sanity-check:
import re
def check_password(password):
pattern = '(?:[a-z]{3}|[A-Z]{3}|\d{3}|[\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]{3})'
return re.search(pattern, password)
passwords = ['a', 'abc', 'ABC', 'aBc', '1bc', '123']
for password in passwords:
if check_password(password):
print 'password failed: ', password
else:
print 'password passed: ', password
Yields:
password passed: a
password failed: abc
password failed: ABC
password passed: aBc
password passed: 1bc
password failed: 123
Hope this helps :)

Using regular expressions to match a word in Python

I am using PRAW to make a reddit bot that takes the comment author of someone who says "alot" and stores their username into a list. I am having troubles with the regular expression and how to get the string to work. Here is my code.
#importing praw for reddit api and time to make intervals
import praw
import time
import re
username = "LewisTheRobot"
password =
r = praw.Reddit(user_agent = "Counts people who say alot")
word_to_match = ['\balot\b']
storage = []
r.login(username, password)
def run_bot():
subreddit = r.get_subreddit("test")
print("Grabbing subreddit")
comments = subreddit.get_comments(limit=200)
print("Grabbing comments")
for comment in comments:
comment_text = comment.body.lower()
isMatch = any(string in comment_text for string in word_to_match)
if comment.id not in storage and isMatch:
print("Match found! Storing username: " + str(comment.author) + " into list.")
storage.append(comment.author)
print("There are currently: " + str(len(storage)) + " people who use 'alot' instead of ' a lot'.")
while True:
run_bot()
time.sleep(5)
so the regular expression I am using looks for the word alot instead of alot as part of a string. Example zealot. Whenever I run this, it will not find a comment that I have made. Any suggestions?
You're checking with string operations, not RE ones, in
isMatch = any(string in comment_text for string in word_to_match)
The first in here checks for a substring -- nothing to do with REs.
Change this to
isMatch = any(re.search(string, comment_text) for string in word_to_match)
Moreover, you have an error in your initialization:
word_to_match = ['\balot\b']
'\b' is the character with code 0x08 (backspace). Always use raw string syntax for RE patterns, to avoid such traps:
word_to_match = [r'\balot\b']
Now you'll have a couple of characters, backslash then b, which RE will interpret to mean "word boundary".
There may be other bugs but I try not to look for more than two bugs per question...:-)

Python RegEx with word boundaries

I am trying to write a login routine for a python script. In doing so, I find the need to pattern match the credentials on a whole word basis. I have attempted to RegEx this, but it is failing for reasons that are unclear to me, but I hope are obvious to someone here. The code and output:
import re
authentry = "testusertestpass"
username = "testuser"
password = "testpass"
combo = "r\'\\b"+username + password + "\\b\'"
testcred = re.search(combo, authentry)
print combo
print authentry
print testcred
r'\btestusertestpass\b'
testusertestpass
None
So my regex test appears, at least to me, to be properly formatted, and should be a direct match against the test string, but is not. Any ideas? Thanks so much for any insight!
try this: it may works.
import re
authentry = "testusertestpass with another text"
username = "testuser"
password = "testpass"
combo = username + password + r'\b'
testcred = re.search(combo, authentry)
print combo
print authentry
print testcred
output:
testusertestpass\b
testusertestpass with another text
<_sre.SRE_Match object at 0x1b8a030>

Categories

Resources