File to LDIF¶
Presentation¶
This script can map any CSV field or LDIF entries attributes to one or more LDIF entries attributes, with specific rules for DN generation and multi-values management.
This is written in Perl and uses:
Net::LDAP::LDIF
Text::CSV (only if CSV as input file)
Text::Unaccent (only if (fmail) macro is used)
Configuration¶
You have to edit the script to modify the configuration:
$ vi file2ldif.pl
Parameters are:
csv_delimiter
: separator of CSV fields
csv_strip_headers
: set to 1 if CSV file has columns name at first line
beginc
: begin delimiter for field container
endc
: end delimiter for field container
map
: all task and mapping rules (see below)
You can define tasks to manage different CSV file structures. For example you can have one CSV file for users and another for groups. So the task name is the first level in the hash map, such as “person” and “group” in this example:
my $map => {
person => { ... }
group => { ... }
};
The task name is important because it will be used as a command line parameter to the script.
Then, in each task, you will define the mapping with the Net::LDAP::Entry syntax.
You will map fields with {i}
, i being the field number for CSV, and the attribute name for LDIF (you can adjust begin and end delimiter in parameters $beginc and $endc).
CSV example¶
If you have a CSV file with 3 columns, you can use {0}, {1} and {2} to map them. Here are two CSV file examples:
example-users.csv
:Login;"First Name";"Last Name" coudot;Clément;OUDOT jclarke;Jonathan;CLARKE
example-groups.csv
:Group name;Default member group1;coudot group2;jclarke
Below is a sample configuration to parse those files:
my $map = {
person => {
dn => 'uid={1},ou=users,dc=example,dc=com',
objectClass => [ 'top', 'person', 'organizationalPerson', 'inetOrgPerson' ],
uid => '{1}',
givenName => '{2}',
sn => '{3}',
cn => '{2} {3}',
},
group => {
dn => 'cn={1},ou=groups,dc=example,dc=com',
objectClass => [ 'top', 'groupOfUniqueNames' ],
cn => '{1}',
uniqueMember => 'uid={2},ou=users,dc=example,dc=com',
},
};
LDIF example¶
Here is a sample entry from an LDIF extract of users:
dn: cn=clide,ou=users,dc=acme,dc=com
objectClass: top
objectClass: person
cn: clide
sn: barrow
employeeType: gangster
You can create one task to reformat the user entry, and another to add the user in a group (whose name depends on employeeType attribute):
my $map = {
person => {
dn => 'uid={cn},ou=users,dc=example,dc=com',
objectClass => [ 'top', 'person', 'organizationalPerson', 'inetOrgPerson' ],
uid => '{cn}',,
sn => '{(uc)sn}',
cn => '{cn}',
},
group => {
change_op => 'add',
dn => 'cn={employeeType},ou=groups,dc=example,dc=com',
uniqueMember => 'uid={cn},ou=users,dc=example,dc=com',
},
};
Change operations¶
By default, generated LDIF uses a changetype: add
, this means you want to add complete entries.
You can set a third command line parameter to use other changetypes:
modify
delete
modrdn
In modify
case, you can add the change_op
field inside a task to determine which change operation will be performed:
add
delete
replace
Macros¶
You can use macros in mapping, for example to lower-case values.
Available macros are:
lc
: lower case
lcfirst
: lower case first letter
uc
: upper case
ucfirst
: upper case first letter
ucfirstlc
: lower case all and upper case fisrt letter
fmail
: format string to fit mail address (lower case, replace spaces by-
and remove accents)
Example:
$map => {
person => {
change_op => replace,
dn => 'uid={(lc)uid},ou=users,dc=example,dc=com,
mail => '{(fmail)givenname}.{(fmail}sn}@example.com',
}
};
Run¶
You can run the script like this:
$ perl file2ldif.pl <taskname> <file> <changetype>
It will produce a taskname.ldif
file.
For our CSV examples, this will be:
$ perl file2ldif.pl person example-users.csv
$ perl file2ldif.pl group example-groups.csv
And resulting LDIF are:
person.ldif:
dn: uid=coudot,ou=users,dc=example,dc=com uid: coudot cn:: Q2zDqW1lbnQgT1VET1Q= sn: OUDOT objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName:: Q2zDqW1lbnQ= dn: uid=jclarke,ou=users,dc=example,dc=com uid: jclarke cn: Jonathan CLARKE sn: CLARKE objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: Jonathan
group.ldif:
dn: cn=group1,ou=groups,dc=example,dc=com cn: group1 uniqueMember: uid=coudot,ou=users,dc=example,dc=com objectClass: top objectClass: groupOfUniqueNames dn: cn=group2,ou=groups,dc=example,dc=com cn: group2 uniqueMember: uid=jclarke,ou=users,dc=example,dc=com objectClass: top objectClass: groupOfUniqueNames
Real life use cases¶
Create test entries¶
Imagine you want to create 1000 test entries with different login and password.
First, use a simple loop to generate a CSV file:
$ echo "login;password" > test-users.csv
$ for i in `seq 1 1000`; do echo "user$i;password$i" >> test-users.csv; done
Then configure the mapping in file2ldif.pl
script:
my $map = {
test => {
dn => 'uid={1},ou=users,dc=example,dc=com',
objectClass => [ 'top', 'person', 'organizationalPerson', 'inetOrgPerson' ],
uid => '{1}',
sn => '{1}',
cn => '{1}',
userPassword => '{2}',
},
};
And run:
$ perl file2ldif.pl test test-users.csv
Add the users in you directory:
$ ldapadd -D cn=manager,dc=example,dc=com -W -f test.ldif
Replace an attribute for all users¶
Imagine you want to change to employeeType value of some users from “gangster” to “cop”.
First you will get an LDIF of concerned users:
$ ldapsearch -b ou=users,dc=example,dc=com '(employeeType=gangster)' -LLL > gangsters.ldif
Then configure the mapping in file2ldif.pl script:
my $map = {
justice => {
change_op => 'replace',
dn => '{dn}',
employeeType => 'cop',
},
};
And run:
$ perl file2ldif.pl justice gangsters.ldif modify
Apply changes in your directory:
$ ldapmodify -D cn=manager,dc=example,dc=com -W -f justice.ldif
Download¶
This script, along with all ldap scripts from this site, can be downloaded from the LTB repository.