414 lines
16 KiB
Python
414 lines
16 KiB
Python
#!/usr/bin/env python
|
|
|
|
"""
|
|
PgToLDAP is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
PgToLDAP is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with PgToLDAP; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
Id: $Id: PgToLDAP.py,v 1.5 2006/12/07 01:40:06 lyz Exp $
|
|
"""
|
|
|
|
import sys, time
|
|
import ldap, ldif, pgdb, ldap.modlist
|
|
from optparse import OptionParser
|
|
import sha
|
|
import base64
|
|
from random import randrange
|
|
|
|
|
|
version = "0.112"
|
|
|
|
def encode_SSHA_password ( password ):
|
|
p_ssha = sha.new( password )
|
|
salt = ''
|
|
|
|
for n in range(7):
|
|
salt += chr(randrange(256))
|
|
|
|
|
|
p_ssha.update( salt )
|
|
p_ssha_base64 = base64.encodestring(p_ssha.digest() + salt + '' )
|
|
return '%s%s' %( '{SSHA}', p_ssha_base64 )
|
|
|
|
|
|
|
|
def parseArgs():
|
|
parser = OptionParser(version="%prog " + version)
|
|
parser.add_option ("-v", "--verbose", dest="verbose", action="store_true", default=False,
|
|
help="Verbose output")
|
|
|
|
parser.add_option ("--pgUser", dest="pgUser", default="postgres",
|
|
help="PostgreSQL User [default: %default]", metavar="USER")
|
|
parser.add_option ("--pgPassword", dest="pgPassword",
|
|
help="PostgreSQL Password", metavar="PASSWORD")
|
|
parser.add_option ("--pgHost", dest="pgHost", default="localhost",
|
|
help="PostgreSQL Host [default: %default]", metavar="HOST")
|
|
parser.add_option ("--pgPort", dest="pgPort", default="5432",
|
|
help="PostgreSQL Port [default: %default]", metavar="PORT")
|
|
parser.add_option ("--pgDb", dest="pgDB",
|
|
help="PostgreSQL Database", metavar="DATABASE")
|
|
|
|
parser.add_option ("-o", "--output", dest="outType", default="file",
|
|
help="Output Type [file|ldap] [default: %default]")
|
|
parser.add_option ("-f", "--file", dest="outFile", default="out.ldif",
|
|
help="Output file [default: %default]", metavar="FILE")
|
|
|
|
parser.add_option ("--ldapUser", dest="ldapUser", default="cn=Directory Manager",
|
|
help="LDAP User [default: %default]", metavar="USER")
|
|
parser.add_option ("--ldapPassword", dest="ldapPassword",
|
|
help="LDAP Password", metavar="PASSWORD")
|
|
parser.add_option ("--ldapHost", dest="ldapHost", default="localhost",
|
|
help="LDAP Host [default: %default]", metavar="HOST")
|
|
parser.add_option ("--ldapPort", dest="ldapPort", default="389",
|
|
help="LDAP Port [default: %default]", metavar="PORT")
|
|
parser.add_option ("--ldapOU", dest="ldapBaseOU", default="dc=fedoraproject, dc=org",
|
|
help="LDAP Base OU [default: %default]", )
|
|
(options, args) = parser.parse_args()
|
|
if options.outType != "file" and options.outType != "ldap":
|
|
parser.error("Output type must be file or ldap")
|
|
return (options, args)
|
|
|
|
def connPostgres(user, password, db, host, port):
|
|
"""Tries to connect to the Postgres db server.
|
|
Will exit with exit code 1 it it fails."""
|
|
global verbose
|
|
if verbose:
|
|
print "Connecting to postgres://%s@%s:%s" % (user, host, port)
|
|
try:
|
|
dbConn = pgdb.connect(user=user,
|
|
password=password,
|
|
database=db,
|
|
host='%s:%s' %(host, port))
|
|
return dbConn
|
|
except:
|
|
print "Error connecting to Postgres server"
|
|
# TODO: Remove exit comment
|
|
sys.exit(1)
|
|
|
|
def connLDAP(user, password, host, port):
|
|
"""Tries to bind to the LDAP server.
|
|
Will exit with exit code 1 it it fails."""
|
|
global verbose
|
|
if verbose:
|
|
print "Connecting to ldap://%s@%s:%s" % (user, host, port)
|
|
try:
|
|
ldapConn = ldap.open(host)
|
|
ldapConn.protocol_version = ldap.VERSION3
|
|
ldapConn.simple_bind_s(user, password)
|
|
return ldapConn
|
|
except ldap.LDAPError, error_message:
|
|
print 'Error connecting to LDAP Server'
|
|
print error_message
|
|
sys.exit(1)
|
|
|
|
def openLdifFile(filename):
|
|
"""Tries to open the output file for writing.
|
|
Will exit with exit code 1 it it fails."""
|
|
global verbose
|
|
if verbose:
|
|
print "Opening output file %s" % filename
|
|
try:
|
|
#ldifWriter = ldif.LDIFWriter(ldap.initialize('ldap://localhost:1390'),filename)
|
|
fileHandel = open (filename,'w')
|
|
|
|
# | __init__(self, output_file, base64_attrs=None, cols=76, line_sep='\n')
|
|
# | output_file
|
|
# | file object for output
|
|
# | base64_attrs
|
|
# | list of attribute types to be base64-encoded in any case
|
|
# | cols
|
|
# | Specifies how many columns a line may have before it's
|
|
# | folded into many lines.
|
|
# | line_sep
|
|
# | String used as line separator
|
|
|
|
|
|
|
|
ldifWriter = ldif.LDIFWriter(fileHandel,"None")
|
|
return ldifWriter
|
|
except ldap.LDAPError, error_message:
|
|
print "Error opening output file: %s" % (filename)
|
|
print error_message
|
|
sys.exit(1)
|
|
|
|
def cleanLDAP(ldapConn, ldapBaseOU):
|
|
"""Removes all existing entries under ou=People and ou=Groups for
|
|
the defined base OU.
|
|
Will exit with exit code 1 if an LDAP error is encountered."""
|
|
global verbose
|
|
if verbose:
|
|
print "Deleting existing users from LDAP"
|
|
try:
|
|
timeout = 0
|
|
result_id = ldapConn.search("ou=People, " + ldapBaseOU,
|
|
ldap.SCOPE_ONELEVEL,
|
|
"cn=*",
|
|
None)
|
|
while 1:
|
|
result_type, result_data = ldapConn.result(result_id, timeout)
|
|
if (result_data == []):
|
|
break
|
|
else:
|
|
if result_type == ldap.RES_SEARCH_ENTRY:
|
|
if verbose:
|
|
print "Deleting LDAP user: " + result_data[0][1]['cn'][0]
|
|
ldapConn.delete_s(result_data[0][0])
|
|
except ldap.LDAPError, error_message:
|
|
print "Error deleting existing users from LDAP"
|
|
print error_message
|
|
sys.exit(1)
|
|
|
|
if verbose:
|
|
print "Deleting existing groups from LDAP"
|
|
try:
|
|
timeout = 0
|
|
result_id = ldapConn.search("ou=Groups, " + ldapBaseOU,
|
|
ldap.SCOPE_ONELEVEL,
|
|
"cn=*",
|
|
None)
|
|
while 1:
|
|
result_type, result_data = ldapConn.result(result_id, timeout)
|
|
if (result_data == []):
|
|
break
|
|
else:
|
|
if result_type == ldap.RES_SEARCH_ENTRY:
|
|
if verbose:
|
|
print "Deleting LDAP group: " + result_data[0][1]['cn'][0]
|
|
ldapConn.delete_s(result_data[0][0])
|
|
except ldap.LDAPError, error_message:
|
|
print "Error deleting existing groups from LDAP"
|
|
print error_message
|
|
sys.exit(1)
|
|
|
|
def main():
|
|
global verbose
|
|
(options, cruft) = parseArgs()
|
|
verbose = options.verbose
|
|
|
|
dbConn = connPostgres(options.pgUser, options.pgPassword,
|
|
options.pgDB, options.pgHost, options.pgPort)
|
|
|
|
# Cleanup LDAP (if necessary)
|
|
if options.outType == "ldap":
|
|
ldapConn = connLDAP(options.ldapUser, options.ldapPassword,
|
|
options.ldapHost, options.ldapPort)
|
|
#cleanLDAP(ldapConn, options.ldapBaseOU)
|
|
else:
|
|
ldifWriter = openLdifFile(options.outFile)
|
|
|
|
# Copy all users from db to ldap/ldif
|
|
# this will to queries and mappings
|
|
|
|
try:
|
|
if verbose:
|
|
print "Selecting all users from Postgres Database"
|
|
userCursor = dbConn.cursor()
|
|
userCursor.execute ("SELECT * FROM person")
|
|
|
|
#id, username, email 2, human_name 3, gpg_keyid 4, ssh_key 5, password 6, comments 7, postal_address 8, telephone 9, facsimile 10, affiliation 11, creation 12, approval_status 13, internal_comments 14, wiki_prefs 15, ircnick 16
|
|
except:
|
|
print "Error selecting users from db"
|
|
raise
|
|
sys.exit(1)
|
|
while 1:
|
|
user = userCursor.fetchone()
|
|
if user == None:
|
|
break
|
|
# TODO: Create method createLdapUserEntry(user)
|
|
#(dn, entry) = createLdapUserEntry(user)
|
|
if options.outType == "ldif":
|
|
ldifWriter.unparse(dn, entry)
|
|
else:
|
|
|
|
|
|
print "Adding ldif info for " + user[3] + "."
|
|
|
|
#userLdif = [["objectClass",["fedoraPerson","organizationalUnit"]] , [ "displayName",[ user[1] ] ] ]
|
|
userLdif = [["objectClass",["fedoraPerson"]] , [ "displayName",[ user[1] ] ] ]
|
|
userLdif.append(["mail",[str(user[2])]])
|
|
userLdif.append(["sn",[str(user[1])]])
|
|
userLdif.append(["fedoraPersonBugzillaMail",[str(user[2])]])
|
|
userLdif.append(["cn",[str(user[1])]])
|
|
userLdif.append(["givenName",[str(user[3])]])
|
|
userLdif.append(["fedoraPersonKeyId",[str(user[4])]])
|
|
userLdif.append(["fedoraPersonSshKey",[str(user[5])]])
|
|
userLdif.append(["userPassword",[encode_SSHA_password(str(user[6]))]])
|
|
userLdif.append(["postalAddress",[str(user[8])]])
|
|
userLdif.append(["telephoneNumber",[str(user[9])]])
|
|
userLdif.append(["fax",[str(user[10]) or "None"]])
|
|
userLdif.append(["o",[str(user[11]) or "None" ]]) # affiliation is set to the o -- another stretch ??
|
|
userLdif.append(["fedoraPersonCreationDate",[str(user[12])]])
|
|
userLdif.append(["fedoraPersonApprovalStatus",[str(user[13])]])
|
|
userLdif.append(["description",[str(user[14])]]) #this one may be a streach -- original field was internal comments
|
|
userLdif.append(["fedoraPersonIrcNick",[str(user[16])]])
|
|
#userLdif.append(["ou",["Roles"]]) Adding an OU instead
|
|
|
|
print userLdif
|
|
#for userKey in userLdif.keys():
|
|
#print "Key Name -> " + userKey
|
|
#print ":::Key Value::: "
|
|
#print userLdif[userKey]
|
|
#ldifWriter.unparse("dc=fedoraproject,dc=org cn=" + user[3] , { userKey : [str(userLdif[userKey])] } )
|
|
|
|
#print userLdif.keys()
|
|
#print userLdif.values()
|
|
ldifWriter.unparse("cn=" + str(user[1]) +",ou=People,dc=fedoraproject,dc=org" , userLdif )
|
|
|
|
roleOuLdif = [["objectClass",["organizationalUnit"]] , [ "ou",[ "Roles" ] ] ]
|
|
ldifWriter.unparse("ou=Roles,cn=" + str(user[1]) +",ou=People,dc=fedoraproject,dc=org" , roleOuLdif )
|
|
|
|
#ldifWriter.unparse("dc=fedoraproject,dc=org, cn=" + user[3] , [ ['ano',['domini']],['uances',['od']] ])
|
|
|
|
#time.sleep (2)
|
|
|
|
|
|
#ldapConn.add_s(dn, entry)
|
|
|
|
userCursor.close()
|
|
|
|
|
|
|
|
# Select all groups from the DB
|
|
|
|
try:
|
|
if verbose:
|
|
print "Selecting all groups from Postgres Database"
|
|
groupCursor = dbConn.cursor()
|
|
groupCursor.execute ("SELECT * FROM project_group")
|
|
|
|
|
|
|
|
except:
|
|
print "Error selecting groups from db"
|
|
raise
|
|
sys.exit(1)
|
|
while 1:
|
|
group = groupCursor.fetchone()
|
|
if group == None:
|
|
break
|
|
# TODO: Create method createLdapGroupEntry(group)
|
|
#(dn, entry) = createLdapGroupEntry(group)
|
|
if options.outType == "ldif":
|
|
ldifWriter.unparse(dn, entry)
|
|
else:
|
|
#ldapConn.add_s(dn, entry)
|
|
|
|
print "Adding group info for %s." % group[7]
|
|
#id0, owner_id1, group_type2, needs_sponsor3, user_can_remove4, prerequisite_id5, joinmsg6, name7
|
|
|
|
uidLookupCursor = dbConn.cursor()
|
|
uidLookupCursor.execute ("SELECT username FROM person where id =" + str(group[1]) )
|
|
owner = uidLookupCursor.fetchone()
|
|
if str(group[5]) != "None" :
|
|
uidLookupCursor.execute ("SELECT name FROM project_group where id =" + str(group[5]) )
|
|
prereq = uidLookupCursor.fetchone()
|
|
print prereq
|
|
else:
|
|
prereq=["None"]
|
|
print owner
|
|
|
|
|
|
#id0, name1, owner_id2, group_type3, needs_sponsor4, user_can_remove5, prerequisite_id6, joinmsg7
|
|
userLdif = [["objectClass",["fedoraGroup"]] ]
|
|
userLdif.append(["cn",[str(group[7])]])
|
|
userLdif.append(["fedoraGroupOwner",owner]) # need to get a cn for this not just the id
|
|
#userLdif.append(["groupOwner",[str(group[2])]]) # need to get a cn for this not just the id
|
|
userLdif.append(["fedoraGroupType",[str(group[3]) or "None" ]])
|
|
|
|
#we're using the boolean type for these. This means they need to be converted to the TRUE and FALSE strings
|
|
|
|
if str(group[3]) == "0" :
|
|
group[3]="FALSE"
|
|
else:
|
|
group[3]="TRUE"
|
|
|
|
if str(group[5]) == "0" :
|
|
group[4]="FALSE"
|
|
else:
|
|
group[4]="TRUE"
|
|
|
|
|
|
userLdif.append(["fedoraGroupNeedsSponsor",[str(group[3])]]) #need to convert to bool
|
|
userLdif.append(["fedoraGroupUserCanRemove",[str(group[4])]]) #need to convert to bool
|
|
#userLdif.append(["groupPrerequisite",[str(group[5])]])
|
|
#userLdif.append(["groupPrerequisite",prereq]) not currently in the schema
|
|
userLdif.append(["fedoraGroupJoinMsg",[str(group[6]) or "None" ]])
|
|
ldifWriter.unparse("cn=" + str(group[7]) +",ou=FedoraGroups,dc=fedoraproject,dc=org" , userLdif )
|
|
|
|
|
|
groupCursor.close()
|
|
|
|
# Select all roles from the DB
|
|
|
|
try:
|
|
if verbose:
|
|
print "Selecting all roles from Postgres Database"
|
|
roleCursor = dbConn.cursor()
|
|
roleCursor.execute ("SELECT * FROM role")
|
|
#person_id, project_group_id, role_type, role_domain, role_status, internal_comments, sponsor_id (Points to a person), creation (TIMESTAMP), approval (TIMESTAMP)
|
|
except:
|
|
print "Error selecting roles from db"
|
|
raise
|
|
sys.exit(1)
|
|
while 1:
|
|
role = roleCursor.fetchone()
|
|
if role == None:
|
|
break
|
|
# TODO: Create method createLdapRoleEntry(group)
|
|
#(dn, entry) = createLdapGroupRole(group)
|
|
if options.outType == "ldif":
|
|
ldifWriter.unparse(dn, entry)
|
|
else:
|
|
#ldapConn.add_s(dn, entry)
|
|
#person_id0, group_project_id1, role_type2, role_domain3, role_status4, internal_comments5, sponsor_id6, creation7, approval8
|
|
|
|
|
|
uidRoleCursor = dbConn.cursor()
|
|
uidRoleCursor.execute ("SELECT username FROM person where id =" + str(role[0]) )
|
|
username = uidRoleCursor.fetchone()
|
|
uidRoleCursor.execute ("SELECT name FROM project_group where id =" + str(role[1]) )
|
|
group = uidRoleCursor.fetchone()
|
|
if str(role[6]) != "None" :
|
|
uidRoleCursor.execute ("SELECT username FROM person where id =" + str(role[6]) )
|
|
sponsor = uidRoleCursor.fetchone()
|
|
else:
|
|
sponsor = ["None"]
|
|
|
|
print "Adding " + str(role[4]) + " role info for " + group[0] + " for user " + username[0] + "."
|
|
#if str(group[6]) != "None" :
|
|
# uidLookupCursor.execute ("SELECT name FROM project_group where id =" + str(group[6]) )
|
|
# prereq = uidLookupCursor.fetchone()
|
|
# print prereq
|
|
#else:
|
|
# prereq=["None"]
|
|
#print owner
|
|
|
|
#person_id0, group_project_id1, role_type2, role_domain3, role_status4, internal_comments5, sponsor_id6, creation7, approval8
|
|
|
|
roleLdif = [["objectClass",["fedoraRole"]] ]
|
|
#roleLdif.append(["cn",[str(group[0]) + str(role[2])]]) #Fix me
|
|
roleLdif.append(["cn",[str(group[0])]]) #Fix me
|
|
roleLdif.append(["fedoraRoleType",[str(role[2])]])
|
|
roleLdif.append(["fedoraRoleDomain",[str(role[3]) or "None" ]])
|
|
roleLdif.append(["fedoraRoleStatus",[str(role[4])]])
|
|
roleLdif.append(["fedoraRoleSponsor",sponsor])
|
|
roleLdif.append(["fedoraRoleCreationDate",[str(role[7]) or "None" ]])
|
|
roleLdif.append(["fedoraRoleApprovalDate",[str(role[8])]])
|
|
|
|
ldifWriter.unparse("cn=" + group[0] + "+fedoraRoleType=" + str(role[2]) + ",ou=Roles,cn=" + username[0] + ",ou=People,dc=fedoraproject,dc=org" , roleLdif )
|
|
|
|
roleCursor.close()
|
|
|
|
sys.exit(1)
|
|
if __name__ == "__main__":
|
|
main()
|