I currently have an app that uses a MySQL backend and I have a client that has profile information for its users stored on it but they also have Active Directory and want to know if I can pull information from that as well to retrieve information from there for a specific profile. I know that you can configure Django for multiple SQL database connections or substitute the authentication backend to Active Directory.
https://docs.djangoproject.com/en/1.9/topics/db/multi-db/
https://pythonhosted.org/django-auth-ldap/
But what I was wondering if I could do both MySQL and Active Directory at the same time or do I just need to connect to the Active Directory externally and retrieve the information that way?
Is this do-able and if so which would be the best way to approach it?
I have a similar situation with a Django site I administer. Here's the Django App I use:
https://github.com/etianen/django-python3-ldap
It allows me to use PostgreSQL for my database, and pull the user metadata I need out of Active Directory and into the user record by mapping fields. It is the best method I have found after several false starts.
If you're just looking to pull data from Active Directory and not into the Django user, here's the package and a code sample I've found to work:
Python 3 package: git+https://github.com/rbarrois/python-ldap.git#py3
Example, which you can modify to work with Django's ORM:
"""
This code provide an example of how to connect to LDAP (specifically, Active Directory)
using Python 3.
Requires python-ldap3, available via the following command:
pip install git+https://github.com/rbarrois/python-ldap.git#py3
"""
import ldap
LDAP_URI = 'ldap://ldap.server.com'
LDAP_DN = 'dc=server,dc=com'
LDAP_USERNAME = 'ldap_user#server.com'
LDAP_PASSWORD = ''
USER_NAME = 'username-to-test'
USER_IN_GROUP = 'CN=SomeGroup,DC=server,DC=com'
USER_NOT_IN_GROUP = 'CN=SomeGroupThatDoesNotExist,DC=server,DC=com'
try:
# Connect to LDAP / Active Directory
ldap_con = ldap.initialize(LDAP_URI)
ldap_con.protocol_version = 3
ldap_con.set_option(ldap.OPT_REFERRALS, 0)
ldap_con.simple_bind_s(LDAP_USERNAME, LDAP_PASSWORD)
# sAMAAccountName is Active Directory's 'username'
user_filter='(&(objectCategory=person)(objectClass=user)(sAMAccountName=' + USER_NAME + '))'
attrs = ['memberOf']
# Perform the search.
ldap_user = ldap_con.search_s(LDAP_DN, ldap.SCOPE_SUBTREE, user_filter, attrs)
# Active Directory returns a list of byte literals. Convert them to strings in a more sensibly named list.
ldap_groups = []
for value in ldap_user[0][1]['memberOf']:
ldap_groups.append(value.decode('utf-8'))
# Print the LDAP groups the user above is a member of, one per line.
for value in ldap_groups:
print(value)
# Perform check to see whether a user is in a group, or explicitly, a user it not in a group.
if USER_IN_GROUP in ldap_groups:
print(USER_NAME + " is a member of " + USER_IN_GROUP)
else:
print(USER_NAME + " is not a member of " + USER_IN_GROUP)
if USER_NOT_IN_GROUP in ldap_groups:
print(USER_NAME + " is a member of " + USER_NOT_IN_GROUP)
else:
print(USER_NAME + " is not a member of " + USER_NOT_IN_GROUP)
# Unbind from LDAP / Active Directory.
ldap_con.unbind()
except ldap.LDAPError:
print(ldap.LDAPError)
These two lines are essential when connecting to Active Directory using an LDAP package:
ldap_con.protocol_version = 3
ldap_con.set_option(ldap.OPT_REFERRALS, 0)
Related
SOLVED ! :)
I used the following to move my mail from somewhere in my inbox into online archives with some important help mentioned below :
import win32com
import os
import sys
outlook = win32com.client.Dispatch('outlook.application')
mapi = outlook.GetNamespace("MAPI")
src = mapi.GetDefaultFolder(6).Folders["tobemoved"]
target = mapi.Folders["Online Archive - XXX"].Folders['Archive']
messages = src.Items
i = range(messages.count, 1, -1)
for x in i:
print(x)
messages(x).Move(target)
`
I have additional folder called
'Online-Archive-Same email address as "inbox" email '
that i currently can't locate it tried to use this link to figure out the enumeration of it . but no luck ..
as i must free up some disk space ill appreciate any help given.
P.S
tried the conventional way - with outlook struggling with connection issues and 22k email to be moved to be archived outlook just giving up on me :) feel free to advise anything that can resolve this issue.
You can access the Office 365 Online Archive folders like this:
Replace the example email with the exact email address you see in outlook.
import win32com.client
import win32com
app = win32com.client.gencache.EnsureDispatch("Outlook.Application")
outlook = app.GetNamespace("MAPI")
outlook_folder = outlook.Folders['Online Archive - Example#email.com'].Folders['Inbox']
item_count = outlook_folder.Items.Count
print(item_count)
180923
On the low (Extended MAPI) level (C++ or Delphi only), Online Archive is just another delegate Exchange mailbox. The only way to distinguish an archive mailbox from yet another delegate mailbox owned by some Exchange user is by reading PR_PROFILE_ALTERNATE_STORE_TYPE property in the archive store profile section - retrieve the store entry id (PR_ENTRYID), then find the matching row in the session stores table (IMAPISession::GetMsgStoresTable). For the matching row (use IMAPISession::CompareEntryIDs), retrieve PR_PROVIDER_UID property. Use its value to call IMAPISession.OpenProfileSection. Read PR_PROFILE_ALTERNATE_STORE_TYPE property from the IProfSect object and check if its value is "Archive" (unlike the store name, is not localized).
If Extended MAPI in C++ or Delphi is not an option, you can either
Try to find a matching store in the Namespace.Stores collection with the name starting with "Online Archive - " and the SMTP address of the user. Since that prefix is locale specific, that is not something I would use in production code.
Use Redemption (I am its author) - it exposes RDOExchangeMailboxStore.IsArchive property. If the archive store is not already opened in Outlook, you can also use RDOSession.GetArchiveMailbox. In VB script:
set rSession = CreateObject("Redemption.RDOSession")
rSession.MAPIOBJECT = Application.Session.MAPIOBJECT
userAddress = rSession.CurrentUser.SMTPAddress
set store = GetOpenArchiveMailboxForUser(userAddress)
if not store is Nothing Then
MsgBox "Found archive store for " & userAddress
Else
MsgBox "Could not find archive store for " & userAddress
End If
function GetOpenArchiveMailboxForUser(SmtpAddress)
set GetOpenArchiveMailboxForUser = Nothing
for each store in rSession.Stores
if TypeName(store) = "RDOExchangeMailboxStore" Then
Debug.Print store.Name & " - " & store.Owner.SMTPAddress & " - " & store.IsArchive
if store.IsArchive and LCase(store.Owner.SMTPAddress) = LCase(SmtpAddress) Then
set GetOpenArchiveMailboxForUser = store
exit for
End If
End If
next
end function
The README for the project at https://github.com/apurvmishra99/facebook-scraper-selenium includes the instruction:
Store your email and password for Facebook login in credentials.txt
This project doesn't contain any code that tries to read or parse credentials.txt, so I assume that the format has to be standard to selenium or to Python.
What exactly is the format this file should be in?
It's not a selenium or python thing. That file was deleted during one of the developer's commits:
I've had a look for you, and if you look in this file in the project: https://github.com/apurvmishra99/facebook-scraper-selenium/blob/master/fb-scraper/settings.py
You can see it gets the email and password:
# User credentials
EMAIL = os.getenv("EMAIL")
PASSWORD = os.getenv("PASSWORD")
os.getenv is python, and does:
os.getenv(key, default=None) Return the value of the environment
variable key if it exists, or default if it doesn’t. key, default and
the result are str.
What you can try is create environment variables called "EMAIL" and "PASSWORD" set the respectively and then run the main.py
Also be aware that in the same settings files the binaries are set as so:
# Required binaries
BROWSER_EXE = '/usr/bin/firefox'
GECKODRIVER = '/usr/bin/geckodriver'
FIREFOX_BINARY = FirefoxBinary(BROWSER_EXE)
You'll need to ensure these reflect your system.
If you delete an user or group in windows AD, it will in "DElETE objects".
I want to use python ldap lib to get them.
Code:
<code>
import ldap
uri = "ldap://10.64.74.17"
user = "XXXXXXXXXX"
password = "XXXXXXXXXXXX"
ldap.set_option(ldap.OPT_REFERRALS, 0)
ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 5)
ldap.protocol_version = 3
ldapClient = ldap.initialize(uri)
ldapClient.simple_bind_s(user, password)
filter = "(&(objectclass=person)(isDeleted=true)(!(objectclass=computer)))"
results = ldapClient.search_s("DC=xx,DC=com", ldap.SCOPE_SUBTREE,filter)
for result in results:
print result
ldapClient.unbind_s()
</code>
It can't show deleted objects.
What's wrong with this code?
You need to add an ldap control to your search : create the request control for the particular operation, and then pass a collection of controls to your search request as an optional parameter.
In your case, this OID for AD is 1.2.840.113556.1.4.417.
LDAP_SERVER_SHOW_DELETED_OID : 1.2.840.113556.1.4.417
Used with an LDAP operation to specify that tombstones and deleted-objects are visible to the operation.
tombstone_control = ('1.2.840.113556.1.4.417',criticality=1)
results = ldapClient.search_s("DC=xx,DC=com", ldap.SCOPE_SUBTREE,filter, [tombstone_control])
You can also scope your search base to CN=Deleted Objects, DC=xx,DC=com as this is where all deleted objects end up. You should make sure your deleted objects are there first. You can use ldp.exe to check.
I'm currently using the shared_contacts_profiles.py script to load contacts from an external system into our Google Shared Domain contacts. I'd like to make the process more automated so I've tried to create a shared contact (with just a full name and email address) using a basic python script. The contact is created but it gets added to the administrator's contacts and not the Directory.
My code is
#!/usr/bin/python
import atom
import gdata.data
import gdata.contacts.client
import gdata.contacts.data
def main():
admin_email = 'admin#mydomain.com'
admin_password = 'P4ssw0rd'
domain_index = admin_email.find('#')
domain = admin_email[domain_index+1:]
contacts_client = gdata.contacts.client.ContactsClient(domain=domain)
contacts_client.client_login(email=admin_email,
password=admin_password,
source='shared_contacts_profiles',
account_type='HOSTED')
new_contact = gdata.contacts.data.ContactEntry()
new_contact.name = gdata.data.Name(
full_name=gdata.data.FullName(text='John Doe'))
new_contact.email.append(gdata.data.Email(address='john.doe#example.com',
primary='true',rel=gdata.data.WORK_REL))
contact_entry = contacts_client.CreateContact(new_contact)
print "Contact's ID: %s" % contact_entry.id.text
if __name__ == '__main__':
main()
I must be missing something fairly simple, but just can't see what it is.
EDIT * I think that shared_contacts_profiles.py sets the domain contact list when it sends batches to Google. I wasn't going to use batches as there are only ever a couple of contacts to add. I also suspect I should be using gdata.contacts.service.ContactsService and not gdata.contacts.client.ContactsClient
Thanks
Dave
In the end I used the original code as shown above with some additions. I needed to get the feed uri for the shared domain contact list and then supply that uri in the CreateContact.
feed_url = contacts_client.GetFeedUri(contact_list=domain, projection='full')
contact_entry = contacts_client.CreateContact(new_contact,insert_uri=feed_url)
Thanks
Dave
We have two zope servers running our company's internal site. One is the live site and one is the dev site. I'm working on writing a python script that moves everything from the dev server to the live server. Right now the process involves a bunch of steps that are done in the zope management interface. I need to make all that automatic so that running one script handles it all. One thing I need to do is export one folder from the live server so that I can reimport it back into the live site after the update. How can I do this from a python script?
We're using Zope 2.8 and python 2.3.4
You can try to use the functions manage_exportObject and manage_importObject located in the file $ZOPE_HOME/lib/python/OFS/ObjectManager.py
Let say we install two Zope 2.8 instances located at:
/tmp/instance/dev for the development server (port 8080)
/tmp/instance/prod for the production server (port 9090)
In the ZMI of the development server, I have created two folders /MyFolder1 and /MyFolder2 containing some page templates. The following Python script exports each folder in .zexp files, and imports them in the ZMI of the production instance:
#!/usr/bin/python
import urllib
import shutil
ids_to_transfer = ['MyFolder1', 'MyFolder2']
for id in ids_to_transfer:
urllib.urlopen('http://admin:password_dev#localhost:8080/manage_exportObject?id=' + id)
shutil.move('/tmp/instance/dev/var/' + id + '.zexp', '/tmp/instance/prod/import/' + id + '.zexp')
urllib.urlopen('http://admin:password_prod#localhost:9090/manage_delObjects?ids=' + id)
urllib.urlopen('http://admin:password_prod#localhost:9090/manage_importObject?file=' + id + '.zexp')
To make this more general and allow copying folders not in the root directory I would do something like this:
#!/usr/bin/python
import urllib
import shutil
username_dev = 'admin'
username_prod = 'admin'
password_dev = 'password_dev'
password_prod = 'password_prod'
url_dev = 'localhost:8080'
url_prod = 'localhost:9090'
paths_and_ids_to_transfer = [('level1/level2/','MyFolder1'), ('level1/','MyFolder2')]
for path, id in ids_to_transfer:
urllib.urlopen('http://%s:%s#%s/%smanage_exportObject?id=%s' % (username_dev, password_dev, url_dev, path, id))
shutil.move('/tmp/instance/dev/var/' + id + '.zexp', '/tmp/instance/prod/import/' + id + '.zexp')
urllib.urlopen('http://%s:%s#%s/%smanage_delObjects?ids=%s' % (username_prod, password_prod, url_prod, path, id))
urllib.urlopen('http://%s:%s#%s/%smanage_importObject?file=%s.zexp' % (username_prod, password_prod, url_prod, path, id))
If I had the rep I would add this to the other answer but alas...
If someone wants to merge them, please go ahead.
If you really move everything you could probably just move the Data.fs instead. But otherwise the import/export above is a good way.