Project

General

Profile

1 2341 sgarg
#!/usr/bin/perl -w
2 4865 walbridge
#
3
#  '$RCSfile$'
4
#  Copyright: 2001 Regents of the University of California
5
#
6
#   '$Author$'
7
#     '$Date$'
8
# '$Revision$'
9
#
10
# This program is free software; you can redistribute it and/or modify
11
# it under the terms of the GNU General Public License as published by
12
# the Free Software Foundation; either version 2 of the License, or
13
# (at your option) any later version.
14
#
15
# This program is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
# GNU General Public License for more details.
19
#
20
# You should have received a copy of the GNU General Public License
21
# along with this program; if not, write to the Free Software
22
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
#
24 2341 sgarg
25
#
26
# This is a web-based application for allowing users to register a new
27
# account for Metacat access.  We currently only support LDAP even
28
# though metacat could potentially support other types of directories.
29 4394 walbridge
30
use lib '../WEB-INF/lib';
31 4080 daigle
use strict;             # turn on strict syntax checking
32
use Template;           # load the template-toolkit module
33 4394 walbridge
use CGI qw/:standard :html3/; # load the CGI module
34 4080 daigle
use Net::LDAP;          # load the LDAP net libraries
35
use Net::SMTP;          # load the SMTP net libraries
36
use Digest::SHA1;       # for creating the password hash
37
use MIME::Base64;       # for creating the password hash
38
use URI;                # for parsing URL syntax
39
use Config::Properties; # for parsing Java .properties files
40
use File::Basename;     # for path name parsing
41 8166 tao
use Captcha::reCAPTCHA; # for protection against spams
42 4394 walbridge
use Cwd 'abs_path';
43 2341 sgarg
44 4080 daigle
# Global configuration paramters
45 4394 walbridge
# This entire block (including skin parsing) could be pushed out to a separate .pm file
46 4080 daigle
my $cgiUrl = $ENV{'SCRIPT_FILENAME'};
47
my $workingDirectory = dirname($cgiUrl);
48
my $metacatProps = "${workingDirectory}/../WEB-INF/metacat.properties";
49
my $properties = new Config::Properties();
50
unless (open (METACAT_PROPERTIES, $metacatProps)) {
51 4394 walbridge
    print "Content-type: text/html\n\n";
52 4080 daigle
    print "Unable to locate Metacat properties. Working directory is set as " .
53
        $workingDirectory .", is this correct?";
54
    exit(0);
55
}
56 2341 sgarg
57 4080 daigle
$properties->load(*METACAT_PROPERTIES);
58 4010 tao
59 4394 walbridge
# local directory configuration
60
my $skinsDir = "${workingDirectory}/../style/skins";
61
my $templatesDir = abs_path("${workingDirectory}/../style/common/templates");
62
my $tempDir = $properties->getProperty('application.tempDir');
63
64
# url configuration
65
my $server = $properties->splitToTree(qr/\./, 'server');
66 7199 leinfelder
my $protocol = 'http://';
67
if ( $properties->getProperty('server.httpPort') eq '443' ) {
68
	$protocol = 'https://';
69
}
70
my $contextUrl = $protocol . $properties->getProperty('server.name');
71 4864 walbridge
if ($properties->getProperty('server.httpPort') ne '80') {
72
        $contextUrl = $contextUrl . ':' . $properties->getProperty('server.httpPort');
73
}
74
$contextUrl = $contextUrl . '/' .  $properties->getProperty('application.context');
75 4394 walbridge
76
my $metacatUrl = $contextUrl . "/metacat";
77
my $cgiPrefix = "/" . $properties->getProperty('application.context') . "/cgi-bin";
78
my $styleSkinsPath = $contextUrl . "/style/skins";
79
my $styleCommonPath = $contextUrl . "/style/common";
80
81 8169 tao
#recaptcha key information
82
my $recaptchaPublicKey=$properties->getProperty('ldap.recaptcha.publickey');
83
my $recaptchaPrivateKey=$properties->getProperty('ldap.recaptcha.privatekey');
84
85 4394 walbridge
my @errorMessages;
86
my $error = 0;
87
88 8181 tao
my $emailVerification= 'emailverification';
89
90 4394 walbridge
# Import all of the HTML form fields as variables
91
import_names('FORM');
92
93
# Must have a config to use Metacat
94
my $skinName = "";
95
if ($FORM::cfg) {
96
    $skinName = $FORM::cfg;
97
} elsif ($ARGV[0]) {
98
    $skinName = $ARGV[0];
99
} else {
100 4747 walbridge
    debug("No configuration set.");
101 4394 walbridge
    print "Content-type: text/html\n\n";
102 4749 walbridge
    print 'LDAPweb Error: The registry requires a skin name to continue.';
103 4394 walbridge
    exit();
104
}
105
106
# Metacat isn't initialized, the registry will fail in strange ways.
107
if (!($metacatUrl)) {
108 4747 walbridge
    debug("No Metacat.");
109 4394 walbridge
    print "Content-type: text/html\n\n";
110
    'Registry Error: Metacat is not initialized! Make sure' .
111 5214 walbridge
        ' MetacatUrl is set correctly in ' .  $skinName . '.properties';
112 4394 walbridge
    exit();
113
}
114
115
my $skinProperties = new Config::Properties();
116
if (!($skinName)) {
117
    $error = "Application misconfigured.  Please contact the administrator.";
118
    push(@errorMessages, $error);
119
} else {
120
    my $skinProps = "$skinsDir/$skinName/$skinName.properties";
121
    unless (open (SKIN_PROPERTIES, $skinProps)) {
122
        print "Content-type: text/html\n\n";
123
        print "Unable to locate skin properties at $skinProps.  Is this path correct?";
124
        exit(0);
125
    }
126
    $skinProperties->load(*SKIN_PROPERTIES);
127
}
128
129
my $config = $skinProperties->splitToTree(qr/\./, 'registry.config');
130
131 4870 walbridge
# XXX HACK: this is a temporary fix to pull out the UCNRS password property from the
132
#           NRS skin instead of metacat.properties. The intent is to prevent editing
133
#           of our core properties file, which is manipulated purely through the web.
134
#           Once organizations are editable, this section should be removed as should
135
#           the properties within nrs/nrs.properties.
136
my $nrsProperties = new Config::Properties();
137
my $nrsProps = "$skinsDir/nrs/nrs.properties";
138
unless (open (NRS_PROPERTIES, $nrsProps)) {
139
    print "Content-type: text/html\n\n";
140
    print "Unable to locate skin properties at $nrsProps.  Is this path correct?";
141
    exit(0);
142
}
143
$nrsProperties->load(*NRS_PROPERTIES);
144
145
my $nrsConfig = $nrsProperties->splitToTree(qr/\./, 'registry.config');
146
147
# XXX END HACK
148
149
150 4394 walbridge
my $searchBase;
151
my $ldapUsername;
152
my $ldapPassword;
153 4728 walbridge
# TODO: when should we use surl instead? Is there a setting promoting one over the other?
154
# TODO: the default tree for accounts should be exposed somewhere, defaulting to unaffiliated
155
my $ldapurl = $properties->getProperty('auth.url');
156 4080 daigle
157
# Java uses miliseconds, Perl expects whole seconds
158 4728 walbridge
my $timeout = $properties->getProperty('ldap.connectTimeLimit') / 1000;
159 4080 daigle
160 2341 sgarg
# Get the CGI input variables
161
my $query = new CGI;
162 4747 walbridge
my $debug = 1;
163 2341 sgarg
164
#--------------------------------------------------------------------------80c->
165
# Set up the Template Toolkit to read html form templates
166
167 4080 daigle
# templates hash, imported from ldap.templates tree in metacat.properties
168
my $templates = $properties->splitToTree(qr/\./, 'ldap.templates');
169 4394 walbridge
$$templates{'header'} = $skinProperties->getProperty("registry.templates.header");
170
$$templates{'footer'} = $skinProperties->getProperty("registry.templates.footer");
171 2341 sgarg
172
# set some configuration options for the template object
173 4394 walbridge
my $ttConfig = {
174
             INCLUDE_PATH => $templatesDir,
175
             INTERPOLATE  => 0,
176
             POST_CHOMP   => 1,
177
             DEBUG        => 1,
178 2341 sgarg
             };
179
180
# create an instance of the template
181 4394 walbridge
my $template = Template->new($ttConfig) || handleGeneralServerFailure($Template::ERROR);
182 2341 sgarg
183 4080 daigle
# custom LDAP properties hash
184
my $ldapCustom = $properties->splitToTree(qr/\./, 'ldap');
185 2341 sgarg
186 4394 walbridge
my $orgProps = $properties->splitToTree(qr/\./, 'organization');
187
my $orgNames = $properties->splitToTree(qr/\./, 'organization.name');
188
# pull out properties available e.g. 'name', 'base'
189
my @orgData = keys(%$orgProps);
190 4870 walbridge
191 4394 walbridge
my @orgList;
192
while (my ($oKey, $oVal) = each(%$orgNames)) {
193
    push(@orgList, $oKey);
194
}
195
196 4866 walbridge
my $authBase = $properties->getProperty("auth.base");
197 4080 daigle
my $ldapConfig;
198
foreach my $o (@orgList) {
199 4394 walbridge
    foreach my $d (@orgData) {
200
        $ldapConfig->{$o}{$d} = $properties->getProperty("organization.$d.$o");
201 4080 daigle
    }
202 4866 walbridge
203 4870 walbridge
    # XXX hack, remove after 1.9
204
    if ($o eq 'UCNRS') {
205
        $ldapConfig->{'UCNRS'}{'base'} = $nrsConfig->{'base'};
206
        $ldapConfig->{'UCNRS'}{'user'} = $nrsConfig->{'username'};
207
        $ldapConfig->{'UCNRS'}{'password'} = $nrsConfig->{'password'};
208
    }
209
210 4866 walbridge
    # set default base
211
    if (!$ldapConfig->{$o}{'base'}) {
212
        $ldapConfig->{$o}{'base'} = $authBase;
213
    }
214
215
    # include filter information. By default, our filters are 'o=$name', e.g. 'o=NAPIER'
216
    # these can be overridden by specifying them in metacat.properties. Non-default configs
217
    # such as UCNRS must specify all LDAP properties.
218
    if ($ldapConfig->{$o}{'base'} eq $authBase) {
219
        my $filter = "o=$o";
220
        if (!$ldapConfig->{$o}{'org'}) {
221
            $ldapConfig->{$o}{'org'} = $filter;
222
        }
223
        if (!$ldapConfig->{$o}{'filter'}) {
224
            $ldapConfig->{$o}{'filter'} = $filter;
225
        }
226
        # also include DN, which is just org + base
227
        if ($ldapConfig->{$o}{'org'}) {
228
            $ldapConfig->{$o}{'dn'} = $ldapConfig->{$o}{'org'} . "," . $ldapConfig->{$o}{'base'};
229
        }
230 4394 walbridge
    } else {
231
        $ldapConfig->{$o}{'dn'} = $ldapConfig->{$o}{'base'};
232
    }
233 4868 walbridge
234
    # set LDAP administrator user account
235 4866 walbridge
    if (!$ldapConfig->{$o}{'user'}) {
236
        $ldapConfig->{$o}{'user'} = $ldapConfig->{'unaffiliated'}{'user'};
237 4865 walbridge
    }
238 4868 walbridge
    # check for a fully qualified LDAP name. If it doesn't exist, append base.
239
    my @userParts = split(',', $ldapConfig->{$o}{'user'});
240
    if (scalar(@userParts) == 1) {
241
        $ldapConfig->{$o}{'user'} = $ldapConfig->{$o}{'user'} . "," . $ldapConfig->{$o}{'base'};
242
    }
243 4866 walbridge
244
    if (!$ldapConfig->{$o}{'password'}) {
245
        $ldapConfig->{$o}{'password'} = $ldapConfig->{'unaffiliated'}{'password'};
246
    }
247 2341 sgarg
}
248
249
#--------------------------------------------------------------------------80c->
250
# Define the main program logic that calls subroutines to do the work
251
#--------------------------------------------------------------------------80c->
252
253
# The processing step we are handling
254 4080 daigle
my $stage = $query->param('stage') || $templates->{'stage'};
255 2341 sgarg
256
my $cfg = $query->param('cfg');
257 4767 walbridge
debug("started with stage $stage, cfg $cfg");
258 2341 sgarg
259
# define the possible stages
260
my %stages = (
261
              'initregister'      => \&handleInitRegister,
262
              'register'          => \&handleRegister,
263
              'registerconfirmed' => \&handleRegisterConfirmed,
264
              'simplesearch'      => \&handleSimpleSearch,
265
              'initaddentry'      => \&handleInitAddEntry,
266
              'addentry'          => \&handleAddEntry,
267
              'initmodifyentry'   => \&handleInitModifyEntry,
268
              'modifyentry'       => \&handleModifyEntry,
269 2972 jones
              'changepass'        => \&handleChangePassword,
270
              'initchangepass'    => \&handleInitialChangePassword,
271 2341 sgarg
              'resetpass'         => \&handleResetPassword,
272 2414 sgarg
              'initresetpass'     => \&handleInitialResetPassword,
273 2341 sgarg
             );
274 4394 walbridge
275 2341 sgarg
# call the appropriate routine based on the stage
276
if ( $stages{$stage} ) {
277
  $stages{$stage}->();
278
} else {
279
  &handleResponseMessage();
280
}
281
282
#--------------------------------------------------------------------------80c->
283
# Define the subroutines to do the work
284
#--------------------------------------------------------------------------80c->
285
286 4728 walbridge
sub fullTemplate {
287
    my $templateList = shift;
288
    my $templateVars = setVars(shift);
289 8166 tao
    my $c = Captcha::reCAPTCHA->new;
290
    my $captcha = 'captcha';
291
    #my $error=null;
292
    my $use_ssl= 1;
293
    #my $options=null;
294 8169 tao
    $templateVars->{$captcha} = $c->get_html($recaptchaPublicKey,undef, $use_ssl, undef);
295 4728 walbridge
    $template->process( $templates->{'header'}, $templateVars );
296
    foreach my $tmpl (@{$templateList}) {
297
        $template->process( $templates->{$tmpl}, $templateVars );
298
    }
299
    $template->process( $templates->{'footer'}, $templateVars );
300
}
301
302 2341 sgarg
#
303
# create the initial registration form
304
#
305
sub handleInitRegister {
306
  my $vars = shift;
307
  print "Content-type: text/html\n\n";
308
  # process the template files:
309 4080 daigle
  fullTemplate(['register'], {stage => "register"});
310 2341 sgarg
  exit();
311
}
312
313
#
314
# process input from the register stage, which occurs when
315
# a user submits form data to create a new account
316
#
317
sub handleRegister {
318
319
    print "Content-type: text/html\n\n";
320 8166 tao
321
322 2341 sgarg
    my $allParams = { 'givenName' => $query->param('givenName'),
323
                      'sn' => $query->param('sn'),
324
                      'o' => $query->param('o'),
325
                      'mail' => $query->param('mail'),
326
                      'uid' => $query->param('uid'),
327
                      'userPassword' => $query->param('userPassword'),
328
                      'userPassword2' => $query->param('userPassword2'),
329
                      'title' => $query->param('title'),
330
                      'telephoneNumber' => $query->param('telephoneNumber') };
331 8166 tao
332
    # Check the recaptcha
333
    my $c = Captcha::reCAPTCHA->new;
334
    my $challenge = $query->param('recaptcha_challenge_field');
335
    my $response = $query->param('recaptcha_response_field');
336
    # Verify submission
337
    my $result = $c->check_answer(
338 8169 tao
        $recaptchaPrivateKey, $ENV{'REMOTE_ADDR'},
339 8166 tao
        $challenge, $response
340
    );
341
342
    if ( $result->{is_valid} ) {
343
        #print "Yes!";
344
        #exit();
345
    }
346
    else {
347
        my $errorMessage = "The verification code is wrong. Please input again.";
348
        fullTemplate(['register'], { stage => "register",
349
                                     allParams => $allParams,
350
                                     errorMessage => $errorMessage });
351
        exit();
352
    }
353
354
355 2341 sgarg
    # Check that all required fields are provided and not null
356
    my @requiredParams = ( 'givenName', 'sn', 'o', 'mail',
357
                           'uid', 'userPassword', 'userPassword2');
358
    if (! paramsAreValid(@requiredParams)) {
359
        my $errorMessage = "Required information is missing. " .
360
            "Please fill in all required fields and resubmit the form.";
361 4080 daigle
        fullTemplate(['register'], { stage => "register",
362
                                     allParams => $allParams,
363
                                     errorMessage => $errorMessage });
364
        exit();
365 2341 sgarg
    } else {
366 2972 jones
        my $o = $query->param('o');
367 4080 daigle
        $searchBase = $ldapConfig->{$o}{'base'};
368 2341 sgarg
    }
369
370
    # Search LDAP for matching entries that already exist
371
    # Some forms use a single text search box, whereas others search per
372
    # attribute.
373
    my $filter;
374
    if ($query->param('searchField')) {
375
376
      $filter = "(|" .
377
                "(uid=" . $query->param('searchField') . ") " .
378
                "(mail=" . $query->param('searchField') . ")" .
379
                "(&(sn=" . $query->param('searchField') . ") " .
380
                "(givenName=" . $query->param('searchField') . "))" .
381
                ")";
382
    } else {
383
      $filter = "(|" .
384
                "(uid=" . $query->param('uid') . ") " .
385
                "(mail=" . $query->param('mail') . ")" .
386
                "(&(sn=" . $query->param('sn') . ") " .
387
                "(givenName=" . $query->param('givenName') . "))" .
388
                ")";
389
    }
390
391
    my @attrs = [ 'uid', 'o', 'cn', 'mail', 'telephoneNumber', 'title' ];
392
    my $found = findExistingAccounts($ldapurl, $searchBase, $filter, \@attrs);
393
394
    # If entries match, send back a request to confirm new-user creation
395
    if ($found) {
396 4080 daigle
      fullTemplate( ['registerMatch', 'register'], { stage => "registerconfirmed",
397
                                                     allParams => $allParams,
398
                                                     foundAccounts => $found });
399 2341 sgarg
    # Otherwise, create a new user in the LDAP directory
400
    } else {
401 8180 tao
        createTemporaryAccount($allParams);
402 2341 sgarg
    }
403
404
    exit();
405
}
406
407
#
408
# process input from the registerconfirmed stage, which occurs when
409
# a user chooses to create an account despite similarities to other
410
# existing accounts
411
#
412
sub handleRegisterConfirmed {
413
414
    my $allParams = { 'givenName' => $query->param('givenName'),
415
                      'sn' => $query->param('sn'),
416 4080 daigle
                      'o' => 'unaffiliated', # only accept unaffiliated registration
417 2341 sgarg
                      'mail' => $query->param('mail'),
418
                      'uid' => $query->param('uid'),
419
                      'userPassword' => $query->param('userPassword'),
420
                      'userPassword2' => $query->param('userPassword2'),
421
                      'title' => $query->param('title'),
422
                      'telephoneNumber' => $query->param('telephoneNumber') };
423
    print "Content-type: text/html\n\n";
424 8180 tao
    createTemporaryAccount($allParams);
425 2341 sgarg
    exit();
426
}
427
428
#
429
# change a user's password upon request
430
#
431
sub handleChangePassword {
432
433
    print "Content-type: text/html\n\n";
434
435
    my $allParams = { 'test' => "1", };
436
    if ($query->param('uid')) {
437
        $$allParams{'uid'} = $query->param('uid');
438
    }
439
    if ($query->param('o')) {
440
        $$allParams{'o'} = $query->param('o');
441 2972 jones
        my $o = $query->param('o');
442
443 4080 daigle
        $searchBase = $ldapConfig->{$o}{'base'};
444 2341 sgarg
    }
445
446
447
    # Check that all required fields are provided and not null
448
    my @requiredParams = ( 'uid', 'o', 'oldpass',
449
                           'userPassword', 'userPassword2');
450
    if (! paramsAreValid(@requiredParams)) {
451
        my $errorMessage = "Required information is missing. " .
452
            "Please fill in all required fields and submit the form.";
453 4080 daigle
        fullTemplate( ['changePass'], { stage => "changepass",
454
                                        allParams => $allParams,
455
                                        errorMessage => $errorMessage });
456
        exit();
457 2341 sgarg
    }
458
459
    # We have all of the info we need, so try to change the password
460
    if ($query->param('userPassword') =~ $query->param('userPassword2')) {
461
462 2972 jones
        my $o = $query->param('o');
463 4080 daigle
        $searchBase = $ldapConfig->{$o}{'base'};
464
        $ldapUsername = $ldapConfig->{$o}{'user'};
465
        $ldapPassword = $ldapConfig->{$o}{'password'};
466 2341 sgarg
467 4080 daigle
        my $dn = "uid=" . $query->param('uid') . "," . $ldapConfig->{$o}{'dn'};;
468 2341 sgarg
        if ($query->param('o') =~ "LTER") {
469 4080 daigle
            fullTemplate( ['registerLter'] );
470 2341 sgarg
        } else {
471
            my $errorMessage = changePassword(
472
                    $dn, $query->param('userPassword'),
473
                    $dn, $query->param('oldpass'), $query->param('o'));
474 2972 jones
            if ($errorMessage) {
475 4080 daigle
                fullTemplate( ['changePass'], { stage => "changepass",
476
                                                allParams => $allParams,
477
                                                errorMessage => $errorMessage });
478
                exit();
479 2341 sgarg
            } else {
480 4080 daigle
                fullTemplate( ['changePassSuccess'], { stage => "changepass",
481
                                                       allParams => $allParams });
482
                exit();
483 2341 sgarg
            }
484
        }
485
    } else {
486
        my $errorMessage = "The passwords do not match. Try again.";
487 4080 daigle
        fullTemplate( ['changePass'], { stage => "changepass",
488
                                        allParams => $allParams,
489
                                        errorMessage => $errorMessage });
490
        exit();
491 2341 sgarg
    }
492
}
493
494
#
495 2414 sgarg
# change a user's password upon request - no input params
496
# only display chagepass template without any error
497
#
498
sub handleInitialChangePassword {
499
    print "Content-type: text/html\n\n";
500
501
    my $allParams = { 'test' => "1", };
502
    my $errorMessage = "";
503 4080 daigle
    fullTemplate( ['changePass'], { stage => "changepass",
504
                                    errorMessage => $errorMessage });
505
    exit();
506 2414 sgarg
}
507
508
#
509 2341 sgarg
# reset a user's password upon request
510
#
511
sub handleResetPassword {
512
513
    print "Content-type: text/html\n\n";
514
515
    my $allParams = { 'test' => "1", };
516
    if ($query->param('uid')) {
517
        $$allParams{'uid'} = $query->param('uid');
518
    }
519
    if ($query->param('o')) {
520
        $$allParams{'o'} = $query->param('o');
521 2972 jones
        my $o = $query->param('o');
522
523 4080 daigle
        $searchBase = $ldapConfig->{$o}{'base'};
524 4868 walbridge
        $ldapUsername = $ldapConfig->{$o}{'user'};
525 4080 daigle
        $ldapPassword = $ldapConfig->{$o}{'password'};
526 2341 sgarg
    }
527
528
    # Check that all required fields are provided and not null
529
    my @requiredParams = ( 'uid', 'o' );
530
    if (! paramsAreValid(@requiredParams)) {
531
        my $errorMessage = "Required information is missing. " .
532
            "Please fill in all required fields and submit the form.";
533 4080 daigle
        fullTemplate( ['resetPass'],  { stage => "resetpass",
534
                                        allParams => $allParams,
535
                                        errorMessage => $errorMessage });
536
        exit();
537 2341 sgarg
    }
538
539
    # We have all of the info we need, so try to change the password
540
    my $o = $query->param('o');
541 4080 daigle
    my $dn = "uid=" . $query->param('uid') . "," . $ldapConfig->{$o}{'dn'};
542 4866 walbridge
    debug("handleResetPassword: dn: $dn");
543 2341 sgarg
    if ($query->param('o') =~ "LTER") {
544 4080 daigle
        fullTemplate( ['registerLter'] );
545
        exit();
546 2341 sgarg
    } else {
547
        my $errorMessage = "";
548
        my $recipient;
549
        my $userPass;
550
        my $entry = getLdapEntry($ldapurl, $searchBase,
551
                $query->param('uid'), $query->param('o'));
552
553
        if ($entry) {
554
            $recipient = $entry->get_value('mail');
555
            $userPass = getRandomPassword();
556 4080 daigle
            $errorMessage = changePassword($dn, $userPass, $ldapUsername, $ldapPassword, $query->param('o'));
557 2341 sgarg
        } else {
558
            $errorMessage = "User not found in database.  Please try again.";
559
        }
560
561
        if ($errorMessage) {
562 4080 daigle
            fullTemplate( ['resetPass'], { stage => "resetpass",
563
                                           allParams => $allParams,
564
                                           errorMessage => $errorMessage });
565
            exit();
566 2341 sgarg
        } else {
567
            my $errorMessage = sendPasswordNotification($query->param('uid'),
568 2972 jones
                    $query->param('o'), $userPass, $recipient, $cfg);
569 4080 daigle
            fullTemplate( ['resetPassSuccess'], { stage => "resetpass",
570
                                                  allParams => $allParams,
571
                                                  errorMessage => $errorMessage });
572
            exit();
573 2341 sgarg
        }
574
    }
575
}
576
577
#
578 2414 sgarg
# reset a user's password upon request- no initial params
579
# only display resetpass template without any error
580
#
581
sub handleInitialResetPassword {
582
    print "Content-type: text/html\n\n";
583
    my $errorMessage = "";
584 4080 daigle
    fullTemplate( ['resetPass'], { stage => "resetpass",
585
                                   errorMessage => $errorMessage });
586
    exit();
587 2414 sgarg
}
588
589
#
590 2341 sgarg
# Construct a random string to use for a newly reset password
591
#
592
sub getRandomPassword {
593
    my $length = shift;
594
    if (!$length) {
595
        $length = 8;
596
    }
597
    my $newPass = "";
598
599
    my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9, qw(! @ $ ^) );
600
    $newPass = join("", @chars[ map { rand @chars } ( 1 .. $length ) ]);
601
    return $newPass;
602
}
603
604
#
605
# Change a password to a new value, binding as the provided user
606
#
607
sub changePassword {
608
    my $userDN = shift;
609
    my $userPass = shift;
610
    my $bindDN = shift;
611
    my $bindPass = shift;
612
    my $o = shift;
613
614 4080 daigle
    my $searchBase = $ldapConfig->{$o}{'base'};
615 4868 walbridge
616 2341 sgarg
    my $errorMessage = 0;
617 3177 tao
    my $ldap;
618 4868 walbridge
619 4771 walbridge
    #if main ldap server is down, a html file containing warning message will be returned
620
    $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
621 4394 walbridge
622 4849 daigle
    if ($ldap) {
623 4868 walbridge
        #$ldap->start_tls( verify => 'require',
624 2972 jones
                      #cafile => '/usr/share/ssl/ldapcerts/cacert.pem');
625 4868 walbridge
        $ldap->start_tls( verify => 'none');
626
        debug("changePassword: attempting to bind to $bindDN");
627
        my $bindresult = $ldap->bind( version => 3, dn => $bindDN,
628 2341 sgarg
                                  password => $bindPass );
629 4868 walbridge
        if ($bindresult->code) {
630
            $errorMessage = "Failed to log in. Are you sure your connection credentails are " .
631
                            "correct? Please correct and try again...";
632
            return $errorMessage;
633
        }
634 2341 sgarg
635 4849 daigle
    	# Find the user here and change their entry
636
    	my $newpass = createSeededPassHash($userPass);
637
    	my $modifications = { userPassword => $newpass };
638 4868 walbridge
      debug("changePass: setting password for $userDN to $newpass");
639 4849 daigle
    	my $result = $ldap->modify( $userDN, replace => { %$modifications });
640 2341 sgarg
641 4849 daigle
    	if ($result->code()) {
642 4866 walbridge
            debug("changePass: error changing password: " . $result->error);
643
        	$errorMessage = "There was an error changing the password:" .
644 2341 sgarg
                           "<br />\n" . $result->error;
645 4849 daigle
    	}
646
    	$ldap->unbind;   # take down session
647
    }
648 2341 sgarg
649
    return $errorMessage;
650
}
651
652
#
653
# generate a Seeded SHA1 hash of a plaintext password
654
#
655
sub createSeededPassHash {
656
    my $secret = shift;
657
658
    my $salt = "";
659
    for (my $i=0; $i < 4; $i++) {
660
        $salt .= int(rand(10));
661
    }
662
663
    my $ctx = Digest::SHA1->new;
664
    $ctx->add($secret);
665
    $ctx->add($salt);
666
    my $hashedPasswd = '{SSHA}' . encode_base64($ctx->digest . $salt ,'');
667
668
    return $hashedPasswd;
669
}
670
671
#
672
# Look up an ldap entry for a user
673
#
674
sub getLdapEntry {
675
    my $ldapurl = shift;
676
    my $base = shift;
677
    my $username = shift;
678
    my $org = shift;
679
680
    my $entry = "";
681
    my $mesg;
682 3177 tao
    my $ldap;
683 4749 walbridge
    debug("ldap server: $ldapurl");
684 4394 walbridge
685
    #if main ldap server is down, a html file containing warning message will be returned
686 4771 walbridge
    $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
687 4849 daigle
688
    if ($ldap) {
689
    	$ldap->start_tls( verify => 'none');
690
    	my $bindresult = $ldap->bind;
691
    	if ($bindresult->code) {
692
        	return $entry;
693
    	}
694 2341 sgarg
695 4849 daigle
    	if($ldapConfig->{$org}{'filter'}){
696 4865 walbridge
            debug("getLdapEntry: filter set, searching for base=$base, " .
697
                  "(&(uid=$username)($ldapConfig->{$org}{'filter'})");
698 4849 daigle
        	$mesg = $ldap->search ( base   => $base,
699 4080 daigle
                filter => "(&(uid=$username)($ldapConfig->{$org}{'filter'}))");
700 4849 daigle
    	} else {
701 4865 walbridge
            debug("getLdapEntry: no filter, searching for $base, (uid=$username)");
702 4849 daigle
        	$mesg = $ldap->search ( base   => $base, filter => "(uid=$username)");
703
    	}
704 3177 tao
705 4849 daigle
    	if ($mesg->count > 0) {
706
        	$entry = $mesg->pop_entry;
707
        	$ldap->unbind;   # take down session
708
    	} else {
709
        	$ldap->unbind;   # take down session
710
        	# Follow references by recursive call to self
711
        	my @references = $mesg->references();
712
        	for (my $i = 0; $i <= $#references; $i++) {
713
            	my $uri = URI->new($references[$i]);
714
            	my $host = $uri->host();
715
            	my $path = $uri->path();
716
            	$path =~ s/^\///;
717
            	$entry = &getLdapEntry($host, $path, $username, $org);
718
            	if ($entry) {
719 4865 walbridge
                    debug("getLdapEntry: recursion found $host, $path, $username, $org");
720 4849 daigle
                	return $entry;
721
            	}
722
        	}
723
    	}
724 2341 sgarg
    }
725
    return $entry;
726
}
727
728
#
729
# send an email message notifying the user of the pw change
730
#
731
sub sendPasswordNotification {
732
    my $username = shift;
733
    my $org = shift;
734
    my $newPass = shift;
735
    my $recipient = shift;
736 2972 jones
    my $cfg = shift;
737 2341 sgarg
738
    my $errorMessage = "";
739
    if ($recipient) {
740 4771 walbridge
        my $mailhost = $properties->getProperty('email.mailhost');
741
        my $sender =  $properties->getProperty('email.sender');
742 2341 sgarg
        # Send the email message to them
743
        my $smtp = Net::SMTP->new($mailhost);
744
        $smtp->mail($sender);
745
        $smtp->to($recipient);
746
747
        my $message = <<"        ENDOFMESSAGE";
748
        To: $recipient
749
        From: $sender
750
        Subject: KNB Password Reset
751
752
        Somebody (hopefully you) requested that your KNB password be reset.
753
        This is generally done when somebody forgets their password.  Your
754
        password can be changed by visiting the following URL:
755
756 4864 walbridge
        $contextUrl/cgi-bin/ldapweb.cgi?stage=changepass&cfg=$cfg
757 2341 sgarg
758
            Username: $username
759
        Organization: $org
760
        New Password: $newPass
761
762
        Thanks,
763
            The KNB Development Team
764
765
        ENDOFMESSAGE
766
        $message =~ s/^[ \t\r\f]+//gm;
767
768
        $smtp->data($message);
769
        $smtp->quit;
770
    } else {
771
        $errorMessage = "Failed to send password because I " .
772
                        "couldn't find a valid email address.";
773
    }
774
    return $errorMessage;
775
}
776
777
#
778
# search the LDAP directory to see if a similar account already exists
779
#
780
sub findExistingAccounts {
781
    my $ldapurl = shift;
782
    my $base = shift;
783
    my $filter = shift;
784
    my $attref = shift;
785 3175 tao
    my $ldap;
786 4847 daigle
    my $mesg;
787 2341 sgarg
788
    my $foundAccounts = 0;
789 4749 walbridge
790 4394 walbridge
    #if main ldap server is down, a html file containing warning message will be returned
791 4868 walbridge
    debug("findExistingAccounts: connecting to $ldapurl, $timeout");
792 4771 walbridge
    $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
793 4845 daigle
    if ($ldap) {
794
    	$ldap->start_tls( verify => 'none');
795
    	$ldap->bind( version => 3, anonymous => 1);
796 4848 daigle
		$mesg = $ldap->search (
797 4845 daigle
			base   => $base,
798
			filter => $filter,
799
			attrs => @$attref,
800
		);
801 2341 sgarg
802 4845 daigle
	    if ($mesg->count() > 0) {
803
			$foundAccounts = "";
804
			my $entry;
805
			foreach $entry ($mesg->all_entries) {
806 5650 walbridge
                # a fix to ignore 'ou=Account' properties which are not usable accounts within Metacat.
807
                # this could be done directly with filters on the LDAP connection, instead.
808
                if ($entry->dn !~ /ou=Account/) {
809
                    $foundAccounts .= "<p>\n<b><u>Account:</u> ";
810
                    $foundAccounts .= $entry->dn();
811
                    $foundAccounts .= "</b><br />\n";
812
                    foreach my $attribute ($entry->attributes()) {
813
                        my $value = $entry->get_value($attribute);
814
                        $foundAccounts .= "$attribute: ";
815
                        $foundAccounts .= $value;
816
                        $foundAccounts .= "<br />\n";
817
                    }
818
                    $foundAccounts .= "</p>\n";
819
                }
820 4845 daigle
			}
821 2341 sgarg
        }
822 4845 daigle
    	$ldap->unbind;   # take down session
823 2341 sgarg
824 4848 daigle
    	# Follow references
825
    	my @references = $mesg->references();
826
    	for (my $i = 0; $i <= $#references; $i++) {
827
        	my $uri = URI->new($references[$i]);
828
        	my $host = $uri->host();
829
        	my $path = $uri->path();
830
        	$path =~ s/^\///;
831
        	my $refFound = &findExistingAccounts($host, $path, $filter, $attref);
832
        	if ($refFound) {
833
            	$foundAccounts .= $refFound;
834
        	}
835
    	}
836 2341 sgarg
    }
837
838
    #print "<p>Checking referrals...</p>\n";
839
    #my @referrals = $mesg->referrals();
840
    #print "<p>Referrals count: ", scalar(@referrals), "</p>\n";
841
    #for (my $i = 0; $i <= $#referrals; $i++) {
842
        #print "<p>Referral: ", $referrals[$i], "</p>\n";
843
    #}
844
845
    return $foundAccounts;
846
}
847
848
#
849
# Validate that we have the proper set of input parameters
850
#
851
sub paramsAreValid {
852
    my @pnames = @_;
853
854
    my $allValid = 1;
855
    foreach my $parameter (@pnames) {
856
        if (!defined($query->param($parameter)) ||
857
            ! $query->param($parameter) ||
858
            $query->param($parameter) =~ /^\s+$/) {
859
            $allValid = 0;
860
        }
861
    }
862
863
    return $allValid;
864
}
865
866
#
867 8175 tao
# Create a temporary account for a user and send an email with a link which can click for the
868
# verification. This is used to protect the ldap server against spams.
869
#
870
sub createTemporaryAccount {
871
    my $allParams = shift;
872 8180 tao
    my $org = $query->param('o');
873
    #my $org = 'unaffiliated';
874 8176 tao
    my $ou = $query->param('ou');
875
    #my $ou = 'LTER';
876 8175 tao
877 8180 tao
    ################## Search LDAP for matching o or ou that already exist
878 8176 tao
    my $tmpSearchBase = 'dc=tmp,' . $authBase;
879 8180 tao
    my $filter;
880 8176 tao
    if($org) {
881
        $filter = "(o"
882 8175 tao
                  . "=" . $org .
883
                 ")";
884 8176 tao
    } else {
885
        $filter = "(ou"
886
                  . "=" . $ou .
887
                 ")";
888
    }
889
    debug("search filer " . $filter);
890
    debug("ldap server ". $ldapurl);
891
    debug("sesarch base " . $tmpSearchBase);
892 8180 tao
    print "Content-type: text/html\n\n";
893 8175 tao
    my @attrs = ['o', 'ou' ];
894
    my $found = searchDirectory($ldapurl, $tmpSearchBase, $filter, \@attrs);
895 8180 tao
896
    my $ldapUsername = $ldapConfig->{$org}{'user'};
897
    my $ldapPassword = $ldapConfig->{$org}{'password'};
898
    debug("LDAP connection to $ldapurl...");
899
900
901 8176 tao
    if(!$found) {
902 8180 tao
        debug("generate the subtree in the dc=tmp===========================");
903 8176 tao
        #need to generate the subtree o or ou
904 8180 tao
        my $dn;
905 8176 tao
        #if main ldap server is down, a html file containing warning message will be returned
906
        my $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
907
        if ($ldap) {
908
            $ldap->start_tls( verify => 'none');
909
            debug("Attempting to bind to LDAP server with dn = $ldapUsername, pwd = $ldapPassword");
910
            $ldap->bind( version => 3, dn => $ldapUsername, password => $ldapPassword );
911
            my $additions;
912
             if($org) {
913
                $additions = [
914
                'o'   => $org,
915
                'objectclass' => ['top', 'organization']
916
                ];
917 8177 tao
                $dn='o=' . $org . ',' . $tmpSearchBase;
918 8176 tao
             } else {
919
                $additions = [
920
                'ou'   => $ou,
921
                'objectclass' => ['top', 'organizationalUnit']
922
                ];
923 8177 tao
                $dn='ou=' . $ou . ',' . $tmpSearchBase;
924 8176 tao
             }
925 8180 tao
            # Do the insertion
926
            debug(" 1-1 here is the additions " . $additions);
927
            debug(" 2-1 here is the additions " . @$additions);
928
            debug(" 3-1 here is the additions " . [@$additions]);
929 8177 tao
            my $result = $ldap->add ( 'dn' => $dn, 'attr' => [ @$additions ]);
930 8176 tao
            if ($result->code()) {
931
                fullTemplate( ['registerFailed', 'register'], { stage => "register",
932
                                                            allParams => $allParams,
933
                                                            errorMessage => $result->error });
934 8180 tao
                $ldap->unbind;   # take down session
935
                exist(0)
936 8176 tao
                # TODO SCW was included as separate errors, test this
937
                #$templateVars    = setVars({ stage => "register",
938
                #                     allParams => $allParams });
939
                #$template->process( $templates->{'register'}, $templateVars);
940
            }
941
            $ldap->unbind;   # take down session
942 8180 tao
        } else {
943 8176 tao
            fullTemplate( ['registerFailed', 'register'], { stage => "register",
944
                                                            allParams => $allParams,
945
                                                            errorMessage => "The ldap server is not available now. Please try it later"});
946
            exit(0);
947 8180 tao
        }
948
949 8176 tao
    }
950 8175 tao
951 8180 tao
    ################create an account under tmp subtree
952 8176 tao
953 8180 tao
    #generate a randomstr for matching the email.
954
    my $randomStr = getRandomPassword(16);
955
    # Create a hashed version of the password
956
    my $shapass = createSeededPassHash($query->param('userPassword'));
957
    my $additions = [
958
                'uid'   => $query->param('uid'),
959
                'cn'   => join(" ", $query->param('givenName'),
960
                                    $query->param('sn')),
961
                'sn'   => $query->param('sn'),
962
                'givenName'   => $query->param('givenName'),
963
                'mail' => $query->param('mail'),
964
                'userPassword' => $shapass,
965
                'employeeNumber' => $randomStr,
966
                'objectclass' => ['top', 'person', 'organizationalPerson',
967
                                'inetOrgPerson', 'uidObject' ]
968
                ];
969
    if (defined($query->param('telephoneNumber')) &&
970
                $query->param('telephoneNumber') &&
971
                ! $query->param('telephoneNumber') =~ /^\s+$/) {
972
                $$additions[$#$additions + 1] = 'telephoneNumber';
973
                $$additions[$#$additions + 1] = $query->param('telephoneNumber');
974
    }
975
    if (defined($query->param('title')) &&
976
                $query->param('title') &&
977
                ! $query->param('title') =~ /^\s+$/) {
978
                $$additions[$#$additions + 1] = 'title';
979
                $$additions[$#$additions + 1] = $query->param('title');
980
    }
981
    my $dn;
982
    if($org) {
983
        $$additions[$#$additions + 1] = 'o';
984
        $$additions[$#$additions + 1] = $org;
985
        $dn='uid=' . $query->param('uid') . ',' . 'o=' . $org . ',' . $tmpSearchBase;
986
    } else {
987
        $$additions[$#$additions + 1] = 'ou';
988
        $$additions[$#$additions + 1] = $ou;
989
        $dn='uid=' . $query->param('uid') . ',' . 'ou=' . $ou . ',' . $tmpSearchBase;
990
    }
991
    my $tmp = 1;
992
    createAccount2($dn, $ldapUsername, $ldapPassword, $additions, $tmp, $allParams);
993 8176 tao
994 8180 tao
995
    ####################send the verification email to the user
996 8181 tao
    my $link = $cgiUrl . 'cfg=' . $skinName . '&' . 'stage=' . $emailVerification . '&' . 'dn=' . $dn . '&' . 'hash=' . $randomStr;
997 8180 tao
998 8181 tao
    my $mailhost = $properties->getProperty('email.mailhost');
999
    my $sender =  $properties->getProperty('email.sender');
1000
    my $recipient = $query->param('mail');
1001
    # Send the email message to them
1002
    my $smtp = Net::SMTP->new($mailhost);
1003
    $smtp->mail($sender);
1004
    $smtp->to($recipient);
1005
1006
    my $message = <<"     ENDOFMESSAGE";
1007
    To: $recipient
1008
    From: $sender
1009
    Subject: KNB Password Reset
1010
1011
    Somebody (hopefully you) registered a KNB account.
1012
    Please click the following link to activate your account.
1013
    If the link doesn't work, please copy the link to your browser:
1014
1015
    $link
1016
1017
    Thanks,
1018
        The KNB Development Team
1019
1020
     ENDOFMESSAGE
1021
     $message =~ s/^[ \t\r\f]+//gm;
1022
1023
     $smtp->data($message);
1024
     $smtp->quit;
1025
1026
    fullTemplate( ['success'] );
1027
1028 8175 tao
}
1029
1030
#
1031 2341 sgarg
# Bind to LDAP and create a new account using the information provided
1032
# by the user
1033
#
1034 8180 tao
sub createAccount2 {
1035
    my $dn = shift;
1036
    my $ldapUsername = shift;
1037
    my $ldapPassword = shift;
1038
    my $additions = shift;
1039
    my $temp = shift; #if it is for a temporary account.
1040
    my $allParams = shift;
1041
1042
    my @failureTemplate;
1043
    if($temp){
1044
        @failureTemplate = ['registerFailed', 'register'];
1045
    } else {
1046
        @failureTemplate = ['registerFailed'];
1047
    }
1048
    print "Content-type: text/html\n\n";
1049
    debug("the dn is " . $dn);
1050
    debug("LDAP connection to $ldapurl...");
1051
    #if main ldap server is down, a html file containing warning message will be returned
1052
    my $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
1053
    if ($ldap) {
1054
            $ldap->start_tls( verify => 'none');
1055
            debug("Attempting to bind to LDAP server with dn = $ldapUsername, pwd = $ldapPassword");
1056
            $ldap->bind( version => 3, dn => $ldapUsername, password => $ldapPassword );
1057
            debug(" 1 here is the additions " . $additions);
1058
            debug(" 2 here is the additions " . @$additions);
1059
            debug(" 3 here is the additions " . [@$additions]);
1060
            my $result = $ldap->add ( 'dn' => $dn, 'attr' => [@$additions ]);
1061
            if ($result->code()) {
1062
                fullTemplate(@failureTemplate, { stage => "register",
1063
                                                            allParams => $allParams,
1064
                                                            errorMessage => $result->error });
1065
                # TODO SCW was included as separate errors, test this
1066
                #$templateVars    = setVars({ stage => "register",
1067
                #                     allParams => $allParams });
1068
                #$template->process( $templates->{'register'}, $templateVars);
1069
            } else {
1070 8181 tao
                #fullTemplate( ['success'] );
1071 8180 tao
            }
1072
            $ldap->unbind;   # take down session
1073
1074
    } else {
1075
         fullTemplate(@failureTemplate, { stage => "register",
1076
                                                            allParams => $allParams,
1077
                                                            errorMessage => "The ldap server is not available now. Please try it later"});
1078
         exit(0);
1079
    }
1080
1081
}
1082
1083
#
1084
# Bind to LDAP and create a new account using the information provided
1085
# by the user
1086
#
1087 2341 sgarg
sub createAccount {
1088
    my $allParams = shift;
1089
1090
    if ($query->param('o') =~ "LTER") {
1091 4080 daigle
        fullTemplate( ['registerLter'] );
1092 2341 sgarg
    } else {
1093
1094
        # Be sure the passwords match
1095
        if ($query->param('userPassword') !~ $query->param('userPassword2')) {
1096
            my $errorMessage = "The passwords do not match. Try again.";
1097 4080 daigle
            fullTemplate( ['registerFailed', 'register'], { stage => "register",
1098
                                                            allParams => $allParams,
1099
                                                            errorMessage => $errorMessage });
1100
            exit();
1101 2341 sgarg
        }
1102
1103 2972 jones
        my $o = $query->param('o');
1104 2341 sgarg
1105 4080 daigle
        my $searchBase = $ldapConfig->{$o}{'base'};
1106
        my $dnBase = $ldapConfig->{$o}{'dn'};
1107 8177 tao
        debug("the dn is " . $dnBase);
1108 4868 walbridge
        my $ldapUsername = $ldapConfig->{$o}{'user'};
1109 4749 walbridge
        my $ldapPassword = $ldapConfig->{$o}{'password'};
1110 4771 walbridge
        debug("LDAP connection to $ldapurl...");
1111 3177 tao
        #if main ldap server is down, a html file containing warning message will be returned
1112 4771 walbridge
        my $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
1113 3177 tao
1114 4849 daigle
        if ($ldap) {
1115
        	$ldap->start_tls( verify => 'none');
1116
        	debug("Attempting to bind to LDAP server with dn = $ldapUsername, pwd = $ldapPassword");
1117
        	$ldap->bind( version => 3, dn => $ldapUsername, password => $ldapPassword );
1118 3177 tao
1119 4849 daigle
        	my $dn = 'uid=' . $query->param('uid') . ',' . $dnBase;
1120
        	debug("Inserting new entry for: $dn");
1121 2341 sgarg
1122 4849 daigle
        	# Create a hashed version of the password
1123
        	my $shapass = createSeededPassHash($query->param('userPassword'));
1124 2341 sgarg
1125 4849 daigle
        	# Do the insertion
1126
        	my $additions = [
1127 2341 sgarg
                'uid'   => $query->param('uid'),
1128
                'o'   => $query->param('o'),
1129
                'cn'   => join(" ", $query->param('givenName'),
1130
                                    $query->param('sn')),
1131
                'sn'   => $query->param('sn'),
1132
                'givenName'   => $query->param('givenName'),
1133
                'mail' => $query->param('mail'),
1134
                'userPassword' => $shapass,
1135
                'objectclass' => ['top', 'person', 'organizationalPerson',
1136
                                'inetOrgPerson', 'uidObject' ]
1137 4849 daigle
            	];
1138
        	if (defined($query->param('telephoneNumber')) &&
1139
            	$query->param('telephoneNumber') &&
1140
            	! $query->param('telephoneNumber') =~ /^\s+$/) {
1141
            	$$additions[$#$additions + 1] = 'telephoneNumber';
1142
            	$$additions[$#$additions + 1] = $query->param('telephoneNumber');
1143
        	}
1144
        	if (defined($query->param('title')) &&
1145
            	$query->param('title') &&
1146
            	! $query->param('title') =~ /^\s+$/) {
1147
            	$$additions[$#$additions + 1] = 'title';
1148
            	$$additions[$#$additions + 1] = $query->param('title');
1149
        	}
1150
        	my $result = $ldap->add ( 'dn' => $dn, 'attr' => [ @$additions ]);
1151 2341 sgarg
1152 4849 daigle
        	if ($result->code()) {
1153
            	fullTemplate( ['registerFailed', 'register'], { stage => "register",
1154 4080 daigle
                                                            allParams => $allParams,
1155
                                                            errorMessage => $result->error });
1156 4849 daigle
            	# TODO SCW was included as separate errors, test this
1157
           	 	#$templateVars    = setVars({ stage => "register",
1158
           	 	#                     allParams => $allParams });
1159
            	#$template->process( $templates->{'register'}, $templateVars);
1160
        	} else {
1161
            	fullTemplate( ['success'] );
1162
        	}
1163
1164
        	$ldap->unbind;   # take down session
1165 2341 sgarg
        }
1166
    }
1167
}
1168
1169
sub handleResponseMessage {
1170
1171
  print "Content-type: text/html\n\n";
1172
  my $errorMessage = "You provided invalid input to the script. " .
1173
                     "Try again please.";
1174 4080 daigle
  fullTemplate( [], { stage => $templates->{'stage'},
1175
                      errorMessage => $errorMessage });
1176
  exit();
1177 2341 sgarg
}
1178
1179
#
1180
# perform a simple search against the LDAP database using
1181
# a small subset of attributes of each dn and return it
1182
# as a table to the calling browser.
1183
#
1184
sub handleSimpleSearch {
1185
1186
    my $o = $query->param('o');
1187
1188 4080 daigle
    my $ldapurl = $ldapConfig->{$o}{'url'};
1189
    my $searchBase = $ldapConfig->{$o}{'base'};
1190 2341 sgarg
1191
    print "Content-type: text/html\n\n";
1192
1193
    my $allParams = {
1194
                      'cn' => $query->param('cn'),
1195
                      'sn' => $query->param('sn'),
1196
                      'gn' => $query->param('gn'),
1197
                      'o'  => $query->param('o'),
1198
                      'facsimiletelephonenumber'
1199
                      => $query->param('facsimiletelephonenumber'),
1200
                      'mail' => $query->param('cmail'),
1201
                      'telephonenumber' => $query->param('telephonenumber'),
1202
                      'title' => $query->param('title'),
1203
                      'uid' => $query->param('uid'),
1204
                      'ou' => $query->param('ou'),
1205
                    };
1206
1207
    # Search LDAP for matching entries that already exist
1208
    my $filter = "(" .
1209
                 $query->param('searchField') . "=" .
1210
                 "*" .
1211
                 $query->param('searchValue') .
1212
                 "*" .
1213
                 ")";
1214
1215
    my @attrs = [ 'sn',
1216
                  'gn',
1217
                  'cn',
1218
                  'o',
1219
                  'facsimiletelephonenumber',
1220
                  'mail',
1221
                  'telephoneNumber',
1222
                  'title',
1223
                  'uid',
1224
                  'labeledURI',
1225
                  'ou' ];
1226
1227
    my $found = searchDirectory($ldapurl, $searchBase, $filter, \@attrs);
1228
1229
    # Send back the search results
1230
    if ($found) {
1231 4080 daigle
      fullTemplate( ('searchResults'), { stage => "searchresults",
1232
                                         allParams => $allParams,
1233
                                         foundAccounts => $found });
1234 2341 sgarg
    } else {
1235
      $found = "No entries matched your criteria.  Please try again\n";
1236
1237 4080 daigle
      fullTemplate( ('searchResults'), { stage => "searchresults",
1238
                                         allParams => $allParams,
1239
                                         foundAccounts => $found });
1240 2341 sgarg
    }
1241
1242
    exit();
1243
}
1244
1245
#
1246
# search the LDAP directory to see if a similar account already exists
1247
#
1248
sub searchDirectory {
1249
    my $ldapurl = shift;
1250
    my $base = shift;
1251
    my $filter = shift;
1252
    my $attref = shift;
1253
1254 4849 daigle
	my $mesg;
1255 2341 sgarg
    my $foundAccounts = 0;
1256 3177 tao
1257
    #if ldap server is down, a html file containing warning message will be returned
1258 4771 walbridge
    my $ldap = Net::LDAP->new($ldapurl, timeout => $timeout) or handleLDAPBindFailure($ldapurl);
1259 3177 tao
1260 4849 daigle
    if ($ldap) {
1261
    	$ldap->start_tls( verify => 'none');
1262
    	$ldap->bind( version => 3, anonymous => 1);
1263
    	my $mesg = $ldap->search (
1264
        	base   => $base,
1265
        	filter => $filter,
1266
        	attrs => @$attref,
1267
    	);
1268 2341 sgarg
1269 4849 daigle
    	if ($mesg->count() > 0) {
1270
        	$foundAccounts = "";
1271
        	my $entry;
1272
        	foreach $entry ($mesg->sorted(['sn'])) {
1273
          		$foundAccounts .= "<tr>\n<td class=\"main\">\n";
1274
          		$foundAccounts .= "<a href=\"" unless
1275 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1276 4849 daigle
         		 $foundAccounts .= $entry->get_value('labeledURI') unless
1277 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1278 4849 daigle
          		$foundAccounts .= "\">\n" unless
1279 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1280 4849 daigle
          		$foundAccounts .= $entry->get_value('givenName');
1281
          		$foundAccounts .= "</a>\n" unless
1282 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1283 4849 daigle
          		$foundAccounts .= "\n</td>\n<td class=\"main\">\n";
1284
          		$foundAccounts .= "<a href=\"" unless
1285 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1286 4849 daigle
          		$foundAccounts .= $entry->get_value('labeledURI') unless
1287 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1288 4849 daigle
          		$foundAccounts .= "\">\n" unless
1289 2341 sgarg
                    (!$entry->get_value('labeledURI'));
1290 4849 daigle
          		$foundAccounts .= $entry->get_value('sn');
1291
          		$foundAccounts .= "</a>\n";
1292
          		$foundAccounts .= "\n</td>\n<td class=\"main\">\n";
1293
          		$foundAccounts .= $entry->get_value('mail');
1294
          		$foundAccounts .= "\n</td>\n<td class=\"main\">\n";
1295
          		$foundAccounts .= $entry->get_value('telephonenumber');
1296
          		$foundAccounts .= "\n</td>\n<td class=\"main\">\n";
1297
          		$foundAccounts .= $entry->get_value('title');
1298
          		$foundAccounts .= "\n</td>\n<td class=\"main\">\n";
1299
          		$foundAccounts .= $entry->get_value('ou');
1300
          		$foundAccounts .= "\n</td>\n";
1301
          		$foundAccounts .= "</tr>\n";
1302
        	}
1303
    	}
1304
    	$ldap->unbind;   # take down session
1305 2341 sgarg
    }
1306
    return $foundAccounts;
1307
}
1308
1309
sub debug {
1310
    my $msg = shift;
1311
1312
    if ($debug) {
1313 4747 walbridge
        print STDERR "LDAPweb: $msg\n";
1314 2341 sgarg
    }
1315
}
1316 3175 tao
1317 4771 walbridge
sub handleLDAPBindFailure {
1318
    my $ldapAttemptUrl = shift;
1319
    my $primaryLdap =  $properties->getProperty('auth.url');
1320
1321
    if ($ldapAttemptUrl eq  $primaryLdap) {
1322
        handleGeneralServerFailure("The main LDAP server $ldapurl is down!");
1323
    } else {
1324
        debug("attempted to bind to nonresponsive LDAP server $ldapAttemptUrl, skipped.");
1325
    }
1326
}
1327
1328 3177 tao
sub handleGeneralServerFailure {
1329
    my $errorMessage = shift;
1330 4728 walbridge
    fullTemplate( ['mainServerFailure'], { errorMessage => $errorMessage });
1331 3175 tao
    exit(0);
1332
   }
1333
1334 4080 daigle
sub setVars {
1335
    my $paramVars = shift;
1336
    # initialize default parameters
1337
    my $templateVars = { cfg => $cfg,
1338 4394 walbridge
                         styleSkinsPath => $contextUrl . "/style/skins",
1339
                         styleCommonPath => $contextUrl . "/style/common",
1340
                         contextUrl => $contextUrl,
1341 4770 daigle
                         cgiPrefix => $cgiPrefix,
1342 4080 daigle
                         orgList => \@orgList,
1343 4394 walbridge
                         config  => $config,
1344 4080 daigle
    };
1345
1346
    # append customized params
1347
    while (my ($k, $v) = each (%$paramVars)) {
1348
        $templateVars->{$k} = $v;
1349
    }
1350
1351
    return $templateVars;
1352
}