Removed /usr/local from CDPATH
[clearscm.git] / cq / enable_ldap
1 #!/usr/bin/perl
2 ################################################################################
3 #
4 # File:         enable_ldap
5 # Description:  This script enables LDAP Authentication on a DB set. LDAP 
6 #               Authentication is supported in Clearquest 2003.06.15 and higher.
7 #
8 # Author:       Andrew@DeFaria.com
9 # Created:      Fri Sep 23 17:27:58 PDT 2005
10 # Language:     Perl
11 # Modules:      Term::ReadLine, Term::ReadKey
12 #
13 # (c) Copyright 2005, Andrew@DeFaria.com, all rights reserved
14 #
15 ################################################################################
16 use strict;
17 use warnings;
18 use Term::ReadLine;
19 use Term::ReadKey;
20
21 $0      =~ /(.*)[\/\\](.*)/;
22 my $me  = (!defined $2) ? $0 : $2;
23
24 my $execute = 1;
25 my $verbose = 0;
26
27 sub Usage {
28   my $msg = shift;
29
30   print "ERROR: $msg\n" if defined $msg;
31
32   print "Usage: $me [-n] [-v] [-u]
33
34 Where:
35
36   -n:   No execute mode (Default Execute)
37   -v:   Turn on verbose mode (Default off)
38   -f:   Configuration file (Default ldap_settings.cfg)
39   -u:   Display this usage
40 ";
41
42   exit 1;
43 } # Usage
44
45 sub verbose {
46   my $msg       = shift;
47
48   print "$msg" if $verbose;
49 } # verbose
50
51 sub error {
52   my $msg       = shift;
53   my $errno     = shift;
54
55   if (!defined $errno) {
56     $msg = "$me: ERROR: $msg";
57   } else {
58     $msg = "$me: ERROR: #$errno: $msg"
59   } # if
60
61   print $msg;
62
63   exit $errno if defined $errno;
64 } # error
65
66 sub DisplayLDAPParms {
67   my %ldap_parms = @_;
68
69   print "\nLDAP Parms:\n";
70
71   foreach (sort (keys (%ldap_parms))) {
72     if (/password/) {
73       print "$_: <password>\n";
74     } else {
75       print "$_: ${ldap_parms {$_}}\n";
76     } # if
77   } # foreach
78 } # DisplayLDAPParms
79
80 sub ParseSettings {
81   my $config_file = shift;
82
83   my %ldap_parms;
84
85   open SETTINGS, $config_file
86     or error "Unable to open $config_file ($!)", 1;
87
88   while (<SETTINGS>) {
89     chomp; chop if /\r/;
90
91     next if /^$/;       # Skip blank lines
92     next if /^\#/;      # and comments
93
94     if (/^dbset:\s*(.*)/i) {
95       $ldap_parms{dbset} = $1;
96     } elsif (/^admin_username:\s*(.*)/i) {
97       $ldap_parms{admin_username} = $1;
98     } elsif (/^admin_password:\s*(.*)/i) {
99       $ldap_parms{admin_password} = $1;
100     } elsif (/^servers:\s*(.*)/i) {
101       $ldap_parms{servers} = $1;
102     } elsif (/^port:\s*(.*)/i) {
103       $ldap_parms{port} = $1;
104     } elsif (/^port:\s*(.*)/i) {
105       $ldap_parms{port} = $1;
106     } elsif (/^search_distinguished_name:\s*(.*)/i) {
107       $ldap_parms{search_distinguished_name} = $1;
108     } elsif (/^search_password:\s*(.*)/i) {
109       $ldap_parms{search_password} = $1;
110     } elsif (/^basedn:\s*(.*)/i) {
111       $ldap_parms{basedn} = $1;
112     } elsif (/^scope:\s*(.*)/i) {
113       $ldap_parms{scope} = $1;
114     } elsif (/^account_attribute:\s*(.*)/i) {
115       $ldap_parms{account_attribute} = $1;
116     } elsif (/^search_filter:\s*(.*)/i) {
117       $ldap_parms{search_filter} = $1;
118     } elsif (/^cq_field:\s*(.*)/i) {
119       $ldap_parms{cq_field} = $1;
120     } elsif (/^attribute_search_entry:\s*(.*)/i) {
121       $ldap_parms{attribute_search_entry} = $1;
122     } elsif (/^test_username:\s*(.*)/i) {
123       $ldap_parms{test_username} = $1;
124     } # if
125   } # while
126
127   close SETTINGS;
128
129   return %ldap_parms;
130 } # ParseSettings
131
132 sub Prompt {
133   my $prefix    = shift; # Prefix or question being asked
134   my $default   = shift; # default value - if any
135   my $suffix    = shift; # Suffix (default ":")
136   my $password  = shift; # Whether or not to turn off echo (default "no");
137
138   $default  = ""        if !defined $default;
139   $suffix   = ":"       if !defined $suffix;
140   $password = "no"      if !defined $password;
141
142   my $value;
143
144   do {
145     print "\n$prefix";
146     print " [$default]" if $default ne "" and $password ne "yes";
147     print "$suffix ";
148
149     if ($password eq "yes") {
150       ReadMode "noecho";
151       $value = ReadLine (0);
152       ReadMode "normal";
153     } else {
154       $value = <STDIN>;
155     } # if
156
157     chomp $value;
158     $value = $default if $value eq "";
159   } until $value ne "";
160
161   return $value
162 } # Prompt
163
164 sub SaveSettings {
165   my $config_file       = shift;
166   my %ldap_parms         = @_;
167
168   open SETTINGS, ">$config_file"
169     or error "Unable to open $config_file ($!)", 2;
170
171   foreach (sort (keys (%ldap_parms))) {
172     if ($_ eq "cq_field") {
173       my $value = "";
174       $value = "CQ_EMAIL"       if $ldap_parms {$_} eq "1";
175       $value = "CQ_FULLNAME"    if $ldap_parms {$_} eq "2";
176       $value = "CQ_LOGIN_NAME"  if $ldap_parms {$_} eq "3";
177       $value = "CQ_MISC_INFO"   if $ldap_parms {$_} eq "4";
178       $value = "CQ_PHONE"       if $ldap_parms {$_} eq "5";
179       print SETTINGS "$_:\t$value\n" if $value ne "";
180     } else {
181       print SETTINGS "$_:\t${ldap_parms {$_}}\n";
182     } # if
183   } # foreach
184
185   close SETTINGS;
186 } # SaveSettings
187
188 sub GetLDAPParms {
189   my %ldap_parms = @_;
190
191   print "DBSET name: This is the name of the Clearquest database set - also
192 known as database connection name. This can be found in the Clearquest
193 Maintainance Tool. Often this is something like \"2003.06.15\".
194 ";
195
196   $ldap_parms {dbset} = Prompt "What is the DBSET name that you wish to enable LDAP on", $ldap_parms {dbset};
197
198   print "
199 Now we need to know the username and password of the administrative
200 user for the $ldap_parms{dbset} DBSET:
201 ";
202
203   $ldap_parms {admin_username} = Prompt "Admin username", $ldap_parms {admin_username};
204   $ldap_parms {admin_password} = Prompt "${ldap_parms {admin_username}}'s password", $ldap_parms {admin_password}, undef, "yes";
205
206   # A: LDAP Server
207   print "\nA: LDAP Server\n";
208   print "
209 Now we need to know the name of the LDAP server to authenticate to.
210
211 What is the host name of the LDAP server? You can specify multiple
212 hosts so that ClearQuest can attempt to connect to an alternate host
213 if it cannot connect to the first one.
214
215 You can specify multiple servers separated by commas.
216 ";
217
218   $ldap_parms {servers} = Prompt "LDAP Server(s)", $ldap_parms {servers};
219
220   # B: LDAP Port
221   print "\nB: LDAP Port\n";
222   print "
223 What is the TCP port number (non-SSL) where the LDAP server listens
224 for communications?
225 ";
226
227   $ldap_parms {port} = Prompt "LDAP port", $ldap_parms {port};
228
229   # C: LDAP Search Username/Password
230   print "\nC: LDAP Distinguished Name for Search Account/Password\n";
231   print "\nDoes the LDAP server allow anonymous searches (Y/n)? ";
232   $_ = <STDIN>; chomp;
233
234   if ($_ !~ /^y|^yes|^$/i) {
235     # C1: LDAP Search username
236     print "
237 What is the distinguished name (DN) of the search account?
238
239 For example: cn=search_user,cn=Users, dc=cqldapmsft,dc=com
240 ";
241
242     $ldap_parms {search_distinguished_name} = Prompt "ClearQuest users. LDAP Search user name", $ldap_parms {search_distinguished_name};
243
244     # C2: LDAP Search passwrod
245     $ldap_parms {search_password} = Prompt "Password", $ldap_parms {search_password}, undef, "yes";
246   } # if
247
248   # D: LDAP BaseDN
249   print "\nD: LDAP BaseDN\n";
250   print "
251 Now here's where things get tricky. LDAP uses a BaseDN or Base
252 Distinguished Name as a sort of path into the LDAP directory. Your
253 LDAP Administrator should be able to provide you with this
254 information.
255
256 What is the base DN from which to start searching for LDAP user
257 directory entries that correspond to ClearQuest users? The base DN
258 must be high enough in the directory hierarchy to include all users
259 that might need to be authenticated; however, a base DN that is too
260 high in the hierarchy might slow login performance.
261 ";
262
263   $ldap_parms {basedn} = Prompt "LDAP BaseDN", $ldap_parms {basedn};
264
265   # E: LDAP Scope
266   while (!defined $ldap_parms {scope} or 
267          ($ldap_parms {scope} ne "sub" and
268           $ldap_parms {scope} ne "one" and
269           $ldap_parms {scope} ne "base")) {
270     print "\nE: LDAP Scope\n";
271     print "
272 What is the scope of the search from the base DN?: sub (subtree); one
273 (one level below); or base (base DN only).
274 ";
275
276     $ldap_parms {scope} = Prompt "LDAP Scope [sub|one|base]", $ldap_parms {scope};
277   } # while
278
279   # F: LDAP Account Attribute
280   print "\nF: LDAP Account Attribute\n";
281   print "
282 What is the LDAP attribute that is used to store the user entry login
283 name values? ClearQuest uses the text string entered in the ClearQuest
284 Login window to search the LDAP directory for a user entry whose LDAP
285 attribute value matches the login name. This LDAP attribute must store
286 unique values for all user entries that ClearQuest searches. You also
287 use this attribute in the answer to the next question.
288
289 For example: samAccountName
290 ";
291
292   $ldap_parms {account_attribute} = Prompt "LDAP Account Attribute", $ldap_parms {account_attribute};
293
294   # G: LDAP Search Filter
295   print "\nG: LDAP Search Filter\n";
296   print "
297 What is the LDAP search filter that ClearQuest must use to select the
298 LDAP user entry based on the attribute specified in the previous
299 question? Use \%login\% as the user's login name; ClearQuest substitutes
300 the text string the user enters in the ClearQuest login window.
301
302 For example: ${ldap_parms {account_attribute}}=\%login\%
303 ";
304
305   $ldap_parms {search_filter} = Prompt "LDAP Search Filter", $ldap_parms {search_filter};
306
307   # H: LDAP Attribute Search Entry
308   print "\nH: LDAP Attribute Search Entry\n";
309   print "
310 What is the LDAP attribute of the user entry to be used to map the
311 user to a corresponding ClearQuest user profile record? You can map an
312 attribute to one of the following ClearQuest user profile record
313 fields: CQ_EMAIL, CQ_FULLNAME, CQ_LOGIN_NAME, CQ_MISC_INFO, or
314 CQ_PHONE. The ClearQuest administrator and LDAP administrator need to
315 work together to determine this mapping.
316
317 First specify the Clearquest field you wish to map to:
318
319 1) CQ_EMAIL
320 2) CQ_FULLNAME
321 3) CQ_LOGIN_NAME
322 4) CQ_MISC_INFO
323 5) CQ_PHONE
324 ";
325
326   my $default_cq_field;
327
328   if ($ldap_parms {cq_field} eq "CQ_EMAIL") {
329     $default_cq_field = 1;
330   } elsif ($ldap_parms {cq_field} eq "CQ_FULLNAME") {
331     $default_cq_field = 2;
332   } elsif ($ldap_parms {cq_field} eq "CQ_LOGIN_NAME") {
333     $default_cq_field = 3;
334   } elsif ($ldap_parms {cq_field} eq "CQ_MISC_INFO") {
335     $default_cq_field = 4;
336   } elsif ($ldap_parms {cq_field} eq "CQ_PHONE") {
337     $default_cq_field = 5;
338   } else {
339     $default_cq_field = 0;
340   } # if
341
342   do {
343     $ldap_parms {cq_field} = Prompt "Enter choice (1-5)", $default_cq_field;
344   } until ($ldap_parms {cq_field} > 0 and $ldap_parms {cq_field} < 6);
345
346   print "\nH: LDAP Attribute Search Entry\n";
347   print "
348 Now enter the corresponding LDAP field that this maps to.
349 ";
350
351   $ldap_parms {attribute_search_entry} = Prompt "LDAP Attribute Search Entry", $ldap_parms {attribute_search_entry};
352
353   # I: LDAP Test Username
354   print "\nI: LDAP Test Username\n";
355   print "
356 What is the login name of a user entry that can be used to validate
357 that ClearQuest can correctly authenticate a user against the LDAP
358 directory? This can be a test account or an actual user account.
359 ";
360
361   $ldap_parms {test_username} = Prompt "LDAP Test Username", $ldap_parms {test_username};
362
363   # J: LDAP Test Password
364   print "\nJ: LDAP Test Password\n";
365   print"
366 What is the password for the user entry specified in the previous
367 question?
368 ";
369
370   $ldap_parms {test_password} = Prompt "LDAP Test Password", $ldap_parms {test_password}, undef, "yes";
371
372   return %ldap_parms;
373 } # GetLDAPParms
374
375 sub SetAuthentication2CQOnly {
376   my %ldap_parms = @_;
377
378   my $cmd = "installutil setauthenticationalgorithm "   .
379             $ldap_parms {dbset}                         . " " .
380             $ldap_parms {admin_username}                        . " " .
381             $ldap_parms {admin_password}                        . " " .
382             "CQ_ONLY";
383
384   verbose "$cmd\n";
385
386   return if !$execute;
387
388   my @output = `$cmd`;
389
390   if ($? ne 0) {
391     print "Error executing $cmd\n";
392
393     foreach (@output) {
394       print $_;
395     } # foreach
396
397     exit 1;
398   } # if
399 } # SetAuthentication2CQOnly
400
401 sub SetLDAPInit {
402   my %ldap_parms = @_;
403
404   my $cmd = "installutil setldapinit "          .
405             $ldap_parms {dbset}                 . " " .
406             $ldap_parms {admin_username}                . " " .
407             $ldap_parms {admin_password}                . " \"" .
408             "-h " . $ldap_parms {servers}               . " " .
409             "-p " . $ldap_parms {port};
410
411   if (defined $ldap_parms {search_distinguished_name}) {
412     $cmd .= " -D " . $ldap_parms {search_distinguished_name} .
413             " -w " . $ldap_parms {search_password};
414   } # if
415
416   $cmd .= "\"";
417
418   verbose "$cmd\n";
419
420   return if !$execute;
421
422   my @output = `$cmd`;
423
424   if ($? ne 0) {
425     print "Error executing $cmd\n";
426
427     foreach (@output) {
428       print $_;
429     } # foreach
430
431     exit 1;
432   } # if
433 } # SetLDAPInit
434
435 sub SetLDAPSearch {
436   my %ldap_parms = @_;
437
438   my $cmd = "installutil setldapsearch "        .
439             $ldap_parms {dbset}                 . " " .
440             $ldap_parms {admin_username}                . " " .
441             $ldap_parms {admin_password}                . " \"" .
442             "-s " . $ldap_parms {scope}         . " " .
443             "-b " . $ldap_parms {basedn}                . " " .
444             $ldap_parms {search_filter}         . "\"";
445
446   print "$cmd\n";
447   return;
448
449   my @output = `$cmd`;
450
451   if ($? ne 0) {
452     print "Error executing $cmd\n";
453
454     foreach (@output) {
455       print $_;
456     } # foreach
457
458     exit 1;
459   } # if
460 } # SetLDAPSearch
461
462 sub MapLDAPFields {
463   my %ldap_parms = @_;
464
465   my @cq_fields = (
466     "CQ_EMAIL",
467     "CQ_FULLNAME",
468     "CQ_LOGIN_NAME",
469     "CQ_MISC_INFO",
470     "CQ_PHONE",
471   );
472
473   my $cq_field = $cq_fields [($ldap_parms {cq_field} - 1)];
474
475   my $cmd = "installutil setcqldapmap "         .
476             $ldap_parms {dbset}                 . " " .
477             $ldap_parms {admin_username}                . " " .
478             $ldap_parms {admin_password}                . " " .
479             $cq_field                           . " " .
480             $ldap_parms {attribute_search_entry};
481
482   verbose "$cmd\n";
483
484   return if !$execute;
485
486   my @output = `$cmd`;
487
488   if ($? ne 0) {
489     print "Error executing $cmd\n";
490
491     foreach (@output) {
492       print $_;
493     } # foreach
494
495     exit 1;
496   } # if
497 } # MapLDAPFields
498
499 sub ValidateLDAPConfig {
500   my %ldap_parms = @_;
501
502   my $cmd = "installutil validateldap "         .
503             $ldap_parms {dbset}                 . " " .
504             $ldap_parms {admin_username}        . " " .
505             $ldap_parms {admin_password}        . " " .
506             $ldap_parms {test_username}         . " " .
507             $ldap_parms {test_password};
508
509   verbose "$cmd\n";
510
511   return if !$execute;
512
513   my @output = `$cmd`;
514
515   if ($? ne 0) {
516     print "Error executing $cmd\n";
517
518     foreach (@output) {
519       print $_;
520     } # foreach
521
522     exit 1;
523   } # if
524
525 } # ValidateLDAPConfig
526
527 sub SetAuthentication2CQFirst {
528   my %ldap_parms = @_;
529   my $cmd = "installutil setauthenticationalgorithm "   .
530             $ldap_parms {dbset}                         . " " .
531             $ldap_parms {admin_username}                . " " .
532             $ldap_parms {admin_password}                . " " .
533             "CQ_FIRST";
534
535   verbose "$cmd\n";
536
537   return if !$execute;
538
539   my @output = `$cmd`;
540
541   if ($? ne 0) {
542     print "Error executing $cmd\n";
543
544     foreach (@output) {
545       print $_;
546     } # foreach
547
548     exit 1;
549   } # if
550 } # SetAuthentication2CQFirst
551
552 my $config_file = "ldap_settings.cfg";
553
554 while ($ARGV [0]) {
555   if ($ARGV [0] eq "-v") {
556     $verbose = 1;
557   } elsif ($ARGV [0] eq "-n") {
558     $execute = 0;
559   } elsif ($ARGV [0] eq "-u") {
560     Usage;
561   } elsif ($ARGV [0] eq "-f") {
562     shift;
563     if ($ARGV [0] eq "") {
564       Usage "Must specify config file after -f";
565     } # if
566     $config_file = $ARGV [0];
567   } else {
568     Usage "Unknown argument found: " . $ARGV [0];
569   } # if
570
571   shift (@ARGV);
572 } # while
573
574 my %ldap_parms = ParseSettings $config_file;
575
576 print "$me: Enable Clearquest LDAP Authentication on a dbset
577
578 First we need to ask some questions...
579
580 ";
581
582 %ldap_parms = GetLDAPParms %ldap_parms;
583
584 DisplayLDAPParms %ldap_parms;
585
586 print "Proceed (Y/n)? ";
587 $_ = <STDIN>; chomp;
588
589 if ($_ =~ /^y|^yes/i) {
590   print "OK, quitting...\n";
591   exit 1;
592 } # if
593
594 if (-f $config_file) {
595   print "Save settings overwriting $config_file (y/N)? ";
596   $_ = <STDIN>; chomp;
597
598   if ($_ =~ /^y|^yes/i) {
599     SaveSettings $config_file, %ldap_parms;
600   } # if
601 } else {
602   SaveSettings $config_file, %ldap_parms;
603 } # if
604
605 SetAuthentication2CQOnly %ldap_parms;
606 SetLDAPInit %ldap_parms;
607 SetLDAPSearch %ldap_parms;
608 MapLDAPFields %ldap_parms;
609 ValidateLDAPConfig %ldap_parms;
610 SetAuthentication2CQFirst %ldap_parms;