global options in python ldap - python

I was playing with python ldap in console and got results which I can't explain. Hope somebody can clarify this for me.
open new python console
import ldap
certfile = '~/ad-server.test.loc.pem'
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, certfile)
who = 'CN=Administrator,CN=Users,dc=test,dc=loc'
passwd = 'passwd'
sslserver = 'ldaps://ad-server.test.loc:636'
#let's say I would like to disable certificate verification for the next connection
ldap.set_option(ldap.OPT_X_TLS_REQUIRECERT, ldap.OPT_X_TLS_ALLOW)
conn = ldap.initialize(server)
conn.simple_bind_s(who, passwd)
(97, [])
#connected successfully
#Now I want to enable certificate verification and try to connect again (this time I should
#fail because I use sef-signed certificate)
#Unbind connection
conn.unbind()
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
conn = ldap.initialize(server)
#Trying to connect
conn.simple_bind_s(who, passwd)
(97, [])
# it is also connected succesfully. Why?
Here is a question,
I turned on certificate verification so it should finish connection attempt with error but it did connection successfully ( I used self-signed certificate that is why attempt to connect should fail) ?
Another example. Do the same things but in different order
open new python console
import ldap
certfile = '~/ad-server.test.loc.pem'
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, certfile)
who = 'CN=Administrator,CN=Users,dc=test,dc=loc'
passwd = 'passwd'
sslserver = 'ldaps://ad-server.test.loc:636'
#Trying to connect using selfsigned certificate
ldap.set_option(ldap.OPT_X_TLS_REQUIRECERT, ldap.OPT_X_TLS_DEMAND)
conn = ldap.initialize(server)
conn.simple_bind_s(who, passwd)
Traceback bla bla bla
ldap.SERVER_DOWN: {'info': 'error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed', 'desc': "Can't contact LDAP server"}
#Ok, let's disable verefication and try again
conn.unbind()
ldap.set_option(ldap.OPT_X_TLS_REQUIRECERT, ldap.OPT_X_TLS_ALLOW)
conn = ldap.initialize(server)
conn.simple_bind_s(who, passwd)
Traceback bla bla bla
ldap.SERVER_DOWN: {'info': 'error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed', 'desc': "Can't contact LDAP server"}
# Even if I disabled verefication connection failed. Why? I expected a positive result.
Can anybody explain this?

We just ran in to a similar problem. Basically, all of the TLS options are set globally by default and stored in a context object used by GNUTLS. The first time a connection is created, that becomes the TLS context that will be used by all subsequent connections in that process.
To change this behavior, the very last TLS-related set_option call you make should be:
connection.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
This is actually done in one of the python-ldap demos.

Related

Does psycopg2.connect inherit the proxy set in this context manager?

I have a Django app below that uses a proxy to connect to an external Postgres database. I had to replace another package with psycopg2 and it works fine locally, but doesn't work when I move onto our production server which is a Heroku app using QuotaguardStatic for proxy purposes. I'm not sure what's wrong here
For some reason, the psycopg2.connect part returns an error with a different IP address. Is it not inheriting the proxy set in the context manager? What would be
from apps.proxy.socks import Socks5Proxy
import requests
PROXY_URL = os.environ['QUOTAGUARDSTATIC_URL']
with Socks5Proxy(url=PROXY_URL) as p:
public_ip = requests.get("http://wtfismyip.com/text").text
print(public_ip) # prints the expected IP address
print('end')
try:
connection = psycopg2.connect(user=EXTERNAL_DB_USERNAME,
password=EXTERNAL_DB_PASSWORD,
host=EXTERNAL_DB_HOSTNAME,
port=EXTERNAL_DB_PORT,
database=EXTERNAL_DB_DATABASE,
cursor_factory=RealDictCursor # To access query results like a dictionary
) # , ssl_context=True
except psycopg2.DatabaseError as e:
logger.error('Unable to connect to Illuminate database')
raise e
Error is:
psycopg2.OperationalError: FATAL: no pg_hba.conf entry for host "12.345.678.910", user "username", database "databasename", SSL on
Basically, the IP address 12.345.678.910 does not match what was printed at the beginning of the context manager where the proxy is set. Do I need to set a proxy another method so that the psycopg2 connection uses it?

Python: Make SFTP connection using proxyhost and proxyport

I have trying to make a SFTP connection using a proxy
and print out the files in the SFTP directory
import pysftp
myHostname = "some.hostname.com"
myUsername = "test"
myPassword = "password"
myProxyHost = "10.10.10.10"
myProxyPort = "1010"
with pysftp.Connection(
host=myHostname,
username=myUsername,
password=myPassword,
proxy=myProxyHost,
proxyport=myProxyPort,
) as sftp:
print("Connection succesfully stablished ... ")
# Switch to a remote directory
sftp.cwd("/test/folder")
directory_structure = sftp.listdir_attr()
# Print data
for attr in directory_structure:
print(attr.filename, attr)
but I am getting a error of 'TypeError: init() got an unexpected keyword argument 'proxy''
could someone show me how to use proxy to make a successful connection.
Based on pysftp.Connection()'s documentation, it does not support proxy or proxyport parameters.
You may have better luck using the underlying Paramiko SFTPClient class – there's a gist over here that seems to have an explanation about proxying with Paramiko.

pysftp connection to host with pem file raise exception paramiko.ssh_exception.BadAuthenticationType

I have to connect to other server in python using the pysftp library, the target server had a key value pair file (pem file), and I've got the following exception:
paramiko.ssh_exception.BadAuthenticationType: ('Bad authentication type', [u'publickey']) (allowed_types=[u'publickey'])
my Code:
import pysftp
pysftp.Connection(host="<IP address>", username="myUserName", password="no password", port=22, private_key="myPemFilePath.pem")
Please any help? and how can I fix such like this issue ?
From the documentation :
import pysftp
with pysftp.Connection('hostname', username='me', private_key='/path/to/keyfile') as sftp:
#
# ... do sftp operations
#
As you can see there is no password= "no password", in ther. Try, by just omitting that in your code, as it probably triggers the use of username/password authentication, skipping your private_key.

pymongo - Unable to connect to mongodb running on EC2

I am connecting to a mongodb server on EC2. The mongo collections require authentication to connect.
I tried everything but I am getting the following error and can't seem to correct it.
from pymongo import MongoClient
mongo_username = "username"
mongo_password = "password"
ssh_user = "user"
ssh_address = "ec2-**********.amazonaws.com"
ssh_port = 22
private_key = "path/to/key/mykey.pem"
def connect_to_mongo():
try:
client = MongoClient("mongodb://"+mongo_username+":"+mongo_password+"#" + ssh_address, ssl = True, ssl_keyfile = private_key)
db = client.myDB
#Should 'admin' be there or 'myDB'? 'admin' at least get if(auth) passed, while 'myDB' doesn't
auth = client.admin.authenticate(mongo_username,mongo_password)
if(auth):
print "MongoDB connection successful"
col = db.myCollection.count()
else:
print "MongoDB authentication failure: Please check the username or password"
client.close()
except Exception as e:
print "MongoDB connection failure: Please check the connection details"
print e
if __name__ == "__main__":
connect_to_mongo()
Output :
MongoDB connection successful
MongoDB connection failure: Please check the connection details
SSL handshake failed: EOF occurred in violation of protocol (_ssl.c:590)
EC2 will close 27017 port by default. Create the in-bound rule as described here and here.
I tried all the options and finally this worked.
client = MongoClient("mongodb://" + ssh_address+":27017") # No private key passing
auth = client.myDB.authenticate(mongo_username,mongo_password) # Authenticate to myDB and not admin
db = client.myDB
So basically I don't need to pass a private key (which is required when doing ssh over to the EC2) since the port was already opened for all incoming IPs ( I guess this was an important fact that I should have known and posted in the question).
Also I was trying to authenticate via the admin DB, which I shouldn't have done because I was given access to myDB only.

Python+LDAP+SSL

Good day.
In advance, I apologize for my English, my national forums and resources did not help.
I am making a script that either changes or creates a user's password in AD
After studying the issue, it became clear that
Password to assign or change can only establish an encrypted connection to the server
Sending the password is only necessary for the encoding utf-16-le
In general there is no problem with the second, but the first has the following problem:
$ python ldap-test-starttls.py
Traceback (most recent call last):
File "ldap-test-starttls.py", line 9, in <module>
l.simple_bind_s( "cn=admin,ou=users,dc=test,dc=ru", "password" )
File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 206, in simple_bind_s
msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 200, in simple_bind
return self._ldap_call(self._l.simple_bind,who,cred,EncodeControlTuples(serverctrls),EncodeControlTuples(clientctrls))
File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 96, in _ldap_call
result = func(*args,**kwargs)
ldap.SERVER_DOWN: {'info': 'A TLS packet with unexpected length was received.', 'desc': "Can't contact LDAP server"}
Script code
import ldap
host = 'ldaps://ldap:636'
l = ldap.initialize(host)
l.set_option( ldap.OPT_X_TLS_DEMAND, True )
l.set_option( ldap.OPT_DEBUG_LEVEL, 255 )
username = 'someUser'
new_pass = 'ne$wP4assw0rd3!'
new_password = ('"%s"' % new_pass).encode("utf-16-le")
l.simple_bind_s( "cn=admin,ou=users,dc=test,dc=ru", "password" )
mod_attrs = [(ldap.MOD_REPLACE, 'unicodePwd', new_password)],[( ldap.MOD_REPLACE, 'unicodePwd', new_password)]
l.modify_s('CN=%s,dc=users,dc=test,dc=ru' % username, mod_attrs)
l.unbind_s()
print "Successfully changed password."
Chances are someone has already solved a similar problem. Yes, the script is running on CentOS and using py32win is not possible.
After looking into it more I was able to come up with a solution:
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
l = ldap.initialize("ldaps://ldap:636")
l.set_option(ldap.OPT_REFERRALS, 0)
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND)
l.set_option(ldap.OPT_X_TLS_DEMAND, True)
l.set_option(ldap.OPT_DEBUG_LEVEL, 255)
l.simple_bind_s("admin#tester.com", "password")
I also think OPT_X_TLS_NEVER will disable TLS, so please don't use that.
set_option(ldap.OPT_X_TLS_NEWCTX, ldap.OPT_ON): LDAP_OPT_X_TLS_NEWCTX has to be called after calling ldap_set_option() to set the TLS attributes, if it's called prior to setting the attributes (as is the current code) then the TLS attributes are not copied into the new TLS context.
So my solution is
l = ldap.initialize("ldaps://ldap:636")
l.set_option(ldap.OPT_REFERRALS, 0)
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND)
l.set_option(ldap.OPT_X_TLS_DEMAND, True)
l.set_option(ldap.OPT_DEBUG_LEVEL, 255)
# This must be the last tls setting to create TLS context.
l.set_option(ldap.OPT_X_TLS_NEWCTX, ldap.OPT_ON)
l.simple_bind_s("admin#tester.com","password")
#see Explain TLS/SSL gotchas
#see TLS does not work for ldap, incorrect TLS & Debug attribute setting in rlm_ldap
PAY much attention to your protocol and port in your connection string:
Using TLS with python-ldap:
# TLS uses string uri 'ldaP://' (NO 's')
# then the method start_tls_s() will transfer to a secure connection
l = ldap.initialize('ldap://localhost:1390',trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)
# Set LDAP protocol version used
l.protocol_version=ldap.VERSION3
# Force cert validation
l.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_DEMAND)
# Set path name of file containing all trusted CA certificates
l.set_option(ldap.OPT_X_TLS_CACERTFILE,CACERTFILE)
# Force libldap to create a new SSL context (must be last TLS option!)
l.set_option(ldap.OPT_X_TLS_NEWCTX,0)
# Now try StartTLS extended operation
l.start_tls_s()
print('***ldap.OPT_X_TLS_VERSION',l.get_option(ldap.OPT_X_TLS_VERSION))
print('***ldap.OPT_X_TLS_CIPHER',l.get_option(ldap.OPT_X_TLS_CIPHER))
# Try an explicit anon bind to provoke failure
l.simple_bind_s('','')
# Close connection
l.unbind_s()
SSL uses 'ldapS://' directly!
And it doesn't use the start_tls_s()
# Create LDAPObject instance
l = ldap.initialize('ldaps://localhost:1391',trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)
# Set LDAP protocol version used
l.protocol_version=ldap.VERSION3
# Force cert validation
l.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_DEMAND)
# Set path name of file containing all trusted CA certificates
l.set_option(ldap.OPT_X_TLS_CACERTFILE,CACERTFILE)
# Force libldap to create a new SSL context (must be last TLS option!)
l.set_option(ldap.OPT_X_TLS_NEWCTX,0)
# Try an explicit anon bind to provoke failure
l.simple_bind_s('','')
print('***ldap.OPT_X_TLS_VERSION',l.get_option(ldap.OPT_X_TLS_VERSION))
print('***ldap.OPT_X_TLS_CIPHER',l.get_option(ldap.OPT_X_TLS_CIPHER))
# Close connection
l.unbind_s()
source: original developers github demo initialize.py

Categories

Resources