Python LDAP write attribute to Active Directory - python

I am able to bind and query Active Directory via python-ldap without any issues except when it comes to adding or modifying attributes on AD. I can add the attribute but the encoding seems to be way off as all the text is garbled.
I've tried encoding my string with utf8 and a few others with no luck.
I've also tried binding with a Domain Admin account along with binding with the user account to which I will be changing an attribute, same result regardless.
Here is the method I use to update an attribute:
class LdapHelpers:
def __init__(self):
import ldap
# set globals
self.server = 'LDAP://dc.mycompany.com'
self.admin_dn = 'CN=Administrator,CN=users,DC=mycompany,DC=com'
self.admin_pass = 'coolpassword'
# init LDAP connection
#ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, 0)
ldap.set_option(ldap.OPT_REFERRALS, 0)
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
ldap.protocol_version = ldap.VERSION3
self.ldap = ldap.initialize(self.server)
def update_attribute(self, attrib, value):
try:
import ldap
conn = self.ldap
conn.simple_bind_s(self.admin_dn, self.admin_pass)
mod_attrs = [( ldap.MOD_REPLACE, "mobile", "6306564123")]
# I have tried other variations of the above
# mod_attrs = [( ldap.MOD_REPLACE, "mobile", "6306564123".encode('utf-8)]
conn.modify_s('CN=Mike Smith,OU=GoogleApps,DC=company,DC=com', mod_attrs)
print 'record updated'
except ldap.LDAPError as e:
return e.message
Doing a ldapsearch via terminal this is what the attribute looks like:
mobile:: MC8sAQAAAAAQNA==
This is what 'Hello World' looks like when I set mobile to it:
mobile:: 77+9ehsCAAAAABDvv70V
I've checked MSDN and it says that ldap attribute is just a Unicode string.
System: Ubuntu 15.10 64bit
Python: 2.7.10
python-ldap==2.4.21
As a side note I can search AD without any issues and parse/display returned user attributes, the issue only seems to be with creating or modifying attributes that this encoding issue comes in to play.

The '=' at the end is often an indicator that it is Base64 encoding. Python has a standard library for encoding/decoding base64 (The link is for Python 3, but Python 2 also has the library). LDAP does indeed use Base64 for something. See The LDAP Data Interchange Format (LDIF).

Take a look at the code from pyad to clarify what to do: https://pypi.python.org/pypi/pyad
It's Python-based.
Another example at already answered question: Use Python script to manage remote LDAP server

Ok I found out what was going on, I was using PyPy 4.0.1 as the interpreter and for some reason this was either causing issues with the python-ldap library and/or encoding for strings.
I switched back to Python 2.7.10 for the interpreter and now the very same modify commands up above work as expected using the python-ldap library. So definitely a word of caution if using PyPy and this particular library....

Related

Exposing a Python Class to COM/VBA

I have a simple python class that I am trying to make com-accessible (e.g., to VBA):
class Foo(object):
_reg_progid_ = 'Foo.Application'
_reg_clsid_ = '{602462c5-e750-4d1c-879b-a0465bebb526}'
_public_methods_ = ['say_hello']
def __init__(self):
pass
def say_hello(self, name):
return f'Hello, {name}'
if __name__=='__main__':
print("Registering COM server")
import win32com.server.register
win32com.server.register.UseCommandLine(Foo)
Several examples indicate this is a pretty standard approach (see here and here).
From python, this appears to be com-accessible. No errors raise, and the output appears as expected:
from comtypes.client import CreateObject
f = CreateObject('Foo.Application')
f.say_hello('David')
When trying to instantiate a Foo from VBA, however, there is an error (Run-time error -2147024770 (8007007e) Automation error The specified module could not be found).
Dim f As Object
Set f = CreateObject("Foo.Application")
I am actually able to resolve this error using the method described in this answer (and this one), specifically doing:
_reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER
And then localserver.serve('{602462c5-e750-4d1c-879b-a0465bebb526}') in the name guard function.
However, in some past applications development work (a long time ago using python 2.7) I know we did not do this part -- instead we used Innosetup to compile an installer from a foo.exe and foo.dll (derived from foo.py probably from py2exe or similar) and other dependencies.
I'm happy (for now) with the solution, but I guess my question is whether this is necessary (as several examples don't do these things) or if there's something else I'm missing (e.g., the installer that I used in a past life actually handled this bit behind-the-scenes with the DLL instead of a .py file?)?
Additional information: OS is 64-bit Windows, running Excel 2013 (32-bit) and python 3.7.4 (32-bit).

How to access the Custom Protocol URL used to invoke the MACOS App which comprises of a single python file (from inside the python code)

I have written a small python file which I am packaging as a .app and installing on macos (latest version). The app is intended to be invoked using a custom protocol similar to "abc://efg/ijk/lmn". The python file employs pyobjc package and intends to use it to implement the business logic. I have option of using, only the Python language to implement my business logic because of legacy reasons.
I have to access the invoking custom URL "abc://efg/ijk/lmn" from inside the python code and parse the values. The "efg" "ijk" and "lmn" in the custom URL will vary and will be used to take some decisions further down the flow.
I have tried multiple things from whatever I could find from the internet but i am unable to access the custom url from with in the python code. The value of sys.argv come as below
sys.argv = ['/Applications/XXXXXApp.app/Contents/MacOS/XXXXXApp', '-psn_0_4490312']
But on windows sys.argv[0] is populated with the custom url.
Will appreciate any directions.
Below code is what I have tried among many other variations of it.
`
from Cocoa import NSObject
mylogger = open(os.path.expanduser("~/Desktop/somefile.txt"), 'w+')
class apple_event_handler(NSObject):
def applicationWillFinishLaunching_(self, notification):
mylogger.write("Will finish ")
def applicationDidFinishLaunching_(self, notification):
mylogger.write("Did Finish")
def handleAppleEvent_withReplyEvent_(self, event, reply_event):
theURL = event.descriptorForKeyword_(fourCharToInt(b'----'))
mylogger.write("********* Handler Invoked !!! *********")
mylogger.write("********* the URL = " + str(theURL))
mylogger.write(*self.args)
aem = NSAppleEventManager.sharedAppleEventManager()
aeh = apple_event_handler.alloc().init()
aem.setEventHandler_andSelector_forEventClass_andEventID_(aeh,
"handleAppleEvent:withReplyEvent:", 1, 1)
`

Python 2.5 informixdb connect parameters

I use Python 2.5 and informixdb. I want to connect with the database, but what are the parameters for the informixdb.connect() method?
I have
Hostname
Port
Databasename
User
Password
But what is the right order? Or how is the dsn String build?
The official documentation does not really help me.
The documentation says i can use
informixdb.connect(dsn)
but they do not explain how a DataSourceString should looks like. What arguments and in which order are needed.
Here is an link to the documentation.
And i know Python 2.5 is very old, but the database does not support Python 3.x i have tried it.
From the documentation at https://sourceforge.net/projects/informixdb/:
To do anything useful with InformixDB one must connect to a database. This is accomplished by calling informixdb.connect:
>>> import informixdb
>>> conn = informixdb.connect('db#daniel', user='me', password='something')
>>> conn
<_informixdb.Connection object at 0xb7d08e90>
informixdb.connect takes three arguments: A dsn which identifies the database and server to connect to, as recognized by ESQL's CONNECT statement (e.g. 'database#server', 'database', '#server') plus an optional user and a corresponding password.
If the dsn doesn't include a servername the value of the environment variable INFORMIXSERVER is used. When connecting without specifying the name of the database no database will be selected. This is useful for setting up a new database from within InformixDB.
Why not use the new "IfxPy" OpenInformix module?
https://github.com/OpenInformix/IfxPy
It has support for both 2.x and 3.x versions of Python.

How to open a newtab page using the webbrowser module in python?

I'm currently trying to open my chrome default new tab page using the webbrowser module in python. I've gotten it to work for opening up random urls, however, when I try chrome://newtab as the url, I just get a message saying that there are "no apps installed to open this type of link".
Here's the relevant bit of code (not much):
import webbrowser
webbrowser.open_new_tab("chrome://newtab")
Yes, chrome is my default browser. Thanks for the help!
Notice that the documentation states that:
Note that on some platforms, trying to open a filename using this function, may work and start the operating system’s associated program. However, this is neither supported nor portable.
It has been a while since I looked at this, but my recollection is that on at least some systems, the way it works under the hood is that is passes the given URI to a system specific built-in command which then opens the URI in the system default for whatever type of URI was passed in. In other words, the default application for a given file type is used. It doesn't matter if the URI points to a local file or not. Therefore, the URI http://examplce.comn/somefile.pdf would open the PDF file on the system default PDF viewer, which may not be the browser. As the documentation notes, this works by accident due to the underlying implementation.
However, in a different OS, such a system specific command doesn't exist, and all URIs will be opened in a web browser.
You failed to mention which OS you are working on (and I forget which OS works which way), but I suspect you are working on an OS of the first type. You might (again depends on which system you have) be able override the default behavior by specifying that a specific browser be used.
You could try setting the environment variable BROWSER as an os.pathsep-separated list of browsers to try in order. Check the value of os.pathsep (import os; print os.pathsep) to see which character is used by your system (usually ':' for POSIX or ';' for Windows) and then use that character to separate items in the list. Of course, you may need to only assign one item to the list (chrome), in which case you don't need to use the separator at all. Like this (be sure to use the correct path for your system):
SET BROWSER="C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
Or, you could try using webrowser.get() to choose your browser programically. However, support for Chrome hasn't been added until Python 3.3. If you are using Python 3.3+, then try:
import webbrowser
chrome = webbrowser.get('google-chrome') # or webbrowser.get('chrome')
chrome.open_new_tab('chrome://newtab')
Note: the above is untested. I don't know which system you have and am therefore not able to replicate your specific setup. YMMV.
Update:
As I now know you are on a pre-Python 3.3 windows machine perhaps the following will help. You can also register a browser so that Python knows about it:
pth = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
webbrowser.register('chrome', None, webbrowser.BackgroundBrowser(pth))
chrome = webbrowser.get('chrome')
chrome.open_new_tab('chrome://newtab')
Seemingly Bulletproof Rock Solid Command Line From Python Option
In development, the methods above worked well for me. Then I moved my code to a production server. I found different flavors of Windows don't all play the same with python's webdriver module - I was very bummed!
I needed a bulletproof method to open auto generated html reports in a specific order.
The code below is a modification of what I did that worked very well.
import subprocess as SP
import time
def display_reports_in_chrome(param_1, param_2):
front = f'start chrome.exe {param_1}\\reports\\' # beginning of command string
reports_list = [
'report_1.html', 'report_2.html', 'report_3.html', 'report_4.html']
url_list = []
for report in reports_list:
url_list.append(f'{front}{param_2}\\{report}') # complete build of commands
for url_cs in url_list: # url_cs = url open command string
time.sleep(0.1) # helps to ensure the tabs order correctly
clo = SP.run(url_cs, shell=True, capture_output=True) # actual shell command
# Stuff below makes sure it worked
check = clo.returncode == 0
error = clo.stderr.decode('utf-8')
url_open_ok = check and not error
err_msg = f'{error}. Let Thom know please!'
assert url_open_ok, err_msg
I should point out that I was enlightened to try this by this answer on SuperUser

How do I have python httplib accept untrusted certs?

How do I have python httplib accept untrusted certs? I created a snake oil/self signed cert on my webserver, and my python client fails to connect as I am using a untrusted cert.
I'd rather problematically fix this in my client code rather than have it trusted on my system.
import httplib
def main():
conn = httplib.HTTPSConnection("127.0.0.1:443")
conn.request("HEAD","/")
res = conn.getresponse()
print res.status, res.reason
data = res.read()
print len(data)
if __name__ == "__main__":
main()
Some of my scripts stopped working after updating my computer. Turns out, this was the problem: https://docs.python.org/2/library/httplib.html#httplib.HTTPSConnection
Changed in version 2.7.9: context was added.
This class now performs all the necessary certificate and hostname checks by default. To revert to the previous, unverified, behavior ssl._create_unverified_context() can be passed to the context parameter.
So if your version of Python is >= 2.7.9 (2.7.10 in my case), you'll likely run into this. To fix it, I updated my call:
httplib.HTTPSConnection(hostname, timeout=5, context=ssl._create_unverified_context())
This is likely the simplest change to retain the same behavior.
From inspecting the Python 2.7.14 source code, you may set an environment variable
PYTHONHTTPSVERIFY=0
and this will cause certificate verification to be disabled by default (this will apply to all requests from your program).
I believe this works from 2.7.12+ - but it does not apply to 3.x.
Ref. PEP 493: Verify HTTPS by default, but allow envvar to override that

Categories