Simple.pm 21.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
package Lemonldap::NG::Portal::Simple;

use strict;
use warnings;

use Exporter 'import';

use Net::LDAP;
use warnings;
use MIME::Base64;
use CGI;
12
use CGI::Cookie;
13
require POSIX;
14
use Lemonldap::NG::Portal::_i18n;
15

16
our $VERSION = '0.84';
17 18 19 20

our @ISA = qw(CGI Exporter);

# Constants
21
use constant {
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
    PE_REDIRECT            => -2,
    PE_DONE                => -1,
    PE_OK                  => 0,
    PE_SESSIONEXPIRED      => 1,
    PE_FORMEMPTY           => 2,
    PE_WRONGMANAGERACCOUNT => 3,
    PE_USERNOTFOUND        => 4,
    PE_BADCREDENTIALS      => 5,
    PE_LDAPCONNECTFAILED   => 6,
    PE_LDAPERROR           => 7,
    PE_APACHESESSIONERROR  => 8,
    PE_FIRSTACCESS         => 9,
    PE_BADCERTIFICATE      => 10,
    PE_PP_ACCOUNT_LOCKED   => 21,
    PE_PP_PASSWORD_EXPIRED => 22,
    PE_CERTIFICATEREQUIRED => 23,
    PE_ERROR               => 24,
39
};
40

Xavier Guimard's avatar
Xavier Guimard committed
41
# EXPORTER PARAMETERS
42
our @EXPORT =
43 44 45
  qw( PE_DONE PE_OK PE_SESSIONEXPIRED PE_FORMEMPTY PE_WRONGMANAGERACCOUNT
  PE_USERNOTFOUND PE_BADCREDENTIALS PE_LDAPCONNECTFAILED PE_LDAPERROR
  PE_APACHESESSIONERROR PE_FIRSTACCESS PE_BADCERTIFICATE PE_REDIRECT
46 47
  PE_PP_ACCOUNT_LOCKED PE_PP_PASSWORD_EXPIRED PE_CERTIFICATEREQUIRED
  PE_ERROR);
48
our %EXPORT_TAGS = ( 'all' => [ @EXPORT, 'import' ], );
49 50 51

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

Xavier Guimard's avatar
Xavier Guimard committed
52
# CONSTRUCTOR
53 54 55 56 57 58 59 60 61 62
sub new {
    my $class = shift;
    my $self  = $class->SUPER::new();
    $self->getConf(@_) or die "Unable to get configuration";
    die("You've to indicate a an Apache::Session storage module !")
      unless ( $self->{globalStorage} );
    eval "require " . $self->{globalStorage};
    die( "Module " . $self->{globalStorage} . " not found in \@INC" ) if ($@);
    die("You've to indicate a domain for cookies") unless ( $self->{domain} );
    $self->{domain} =~ s/^([^\.])/.$1/;
63 64 65 66 67
    $self->{ldapServer}         ||= 'localhost';
    $self->{ldapPort}           ||= 389;
    $self->{securedCookie}      ||= 0;
    $self->{cookieName}         ||= "lemonldap";
    $self->{ldapPpolicyControl} ||= 0;
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    $self->{authentication}     ||= 'LDAP';
    $self->{authentication} =~ s/^ldap/LDAP/;

    # Authentication module is required and has to be in @ISA
    my $tmp = 'Lemonldap::NG::Portal::Auth' .  $self->{authentication};
    $tmp =~ s/\s.*$//;
    eval "require $tmp";
    die($@) if ($@);
    push @ISA, $tmp;

    # $self->{authentication} can contains arguments (key1 = scalar_value;
    # key2 = ...)
    $tmp = $self->{authentication};
    $tmp =~ s/^\w+\s*//;
    my %h = split( /\s*[=;]\s*/, $tmp) if($tmp);
    %$self = ( %h, %$self );

    $self->authInit();
86 87 88
    return $self;
}

Xavier Guimard's avatar
Xavier Guimard committed
89
# getConf basic, copy all parameters in $self. Overloaded in SharedConf.pm
90 91 92 93 94 95 96 97 98 99 100 101 102
sub getConf {
    my ($self) = shift;
    my %args;
    if ( ref( $_[0] ) ) {
        %args = %{ $_[0] };
    }
    else {
        %args = @_;
    }
    %$self = ( %$self, %args );
    1;
}

103
# error calls i18n.pm to dysplay error in the wanted language
104 105
sub error {
    my $self = shift;
106
    return &Lemonldap::NG::Portal::_i18n::error( $self->{error},
107
        shift || $ENV{HTTP_ACCEPT_LANGUAGE} );
108 109
}

110
# Private sub used to bind to LDAP server both with Lemonldap::NG account and user
Xavier Guimard's avatar
Xavier Guimard committed
111
# credentials if LDAP authentication is used
112
sub _bind {
113
    my ( $self, $ldap, $dn, $password ) = @_;
114 115 116 117 118 119 120 121 122 123 124 125 126
    my $mesg;
    if ( $dn and $password ) {    # named bind
        $mesg = $ldap->bind( $dn, password => $password );
    }
    else {                        # anonymous bind
        $mesg = $ldap->bind();
    }
    if ( $mesg->code() != 0 ) {
        return 0;
    }
    return 1;
}

Xavier Guimard's avatar
Xavier Guimard committed
127
# CGI.pm overload to add Lemonldap::NG cookie
128 129 130 131 132 133 134 135 136 137
sub header {
    my $self = shift;
    if ( $self->{cookie} ) {
        $self->SUPER::header( @_, -cookie => $self->{cookie} );
    }
    else {
        $self->SUPER::header(@_);
    }
}

Xavier Guimard's avatar
Xavier Guimard committed
138
# CGI.pm overload to add Lemonldap::NG cookie
139 140
sub redirect {
    my $self = shift;
141 142
    if ( $self->{cookie} ) {
        $self->SUPER::redirect( @_, -cookie => $self->{cookie} );
143 144 145 146 147 148
    }
    else {
        $self->SUPER::redirect(@_);
    }
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
# Externalise functions execution
sub _subProcess {
    my $self = shift;
    my @subs = @_;
    my $err  = undef;

    foreach my $sub (@subs) {
        if ( $self->{$sub} ) {
            last if ( $err = &{ $self->{$sub} }($self) );
        }
        else {
            last if ( $err = $self->$sub );
        }
    }

    return $err;
}

167 168 169 170 171 172 173 174 175
sub updateStatus {
    my ($self) = @_;
    print $Lemonldap::NG::Handler::Simple::statusPipe (
        $self->{user} ? $self->{user} : $ENV{REMOTE_ADDR} )
      . " => $ENV{SERVER_NAME}$ENV{SCRIPT_NAME} "
      . $self->{error} . "\n"
      if ($Lemonldap::NG::Handler::Simple::statusPipe);
}

176 177 178 179
###############################################################
# MAIN subroutine: call all steps until one returns something #
#                  different than PE_OK                       #
###############################################################
180

181 182 183
# extractFormInfo, setAuthSessionInfo and authenticate must be implemented in
# auth modules

Xavier Guimard's avatar
Xavier Guimard committed
184 185 186
sub process {
    my ($self) = @_;
    $self->{error} = PE_OK;
187
    $self->{error} = $self->_subProcess(
188
        qw(controlUrlOrigin controlExistingSession extractFormInfo formateParams
189 190 191
          formateFilter connectLDAP bind search setAuthSessionInfo
          setSessionInfo setMacros setGroups authenticate store unbind
          buildCookie log autoRedirect)
192 193 194
    );
    $self->updateStatus;
    return ( ( $self->{error} > 0 ) ? 0 : 1 );
Xavier Guimard's avatar
Xavier Guimard committed
195 196 197
}

# 1. If the user was redirected here, we have to load 'url' parameter
198 199 200 201 202 203 204 205
sub controlUrlOrigin {
    my $self = shift;
    if ( $self->param('url') ) {
        $self->{urldc} = decode_base64( $self->param('url') );
    }
    PE_OK;
}

Xavier Guimard's avatar
Xavier Guimard committed
206
# 2. Control existing sessions
207 208
# what to do with existing sessions ?
#       - delete and create a new session (default)
Xavier Guimard's avatar
Xavier Guimard committed
209
#       - re-authentication (actual scheme)
210 211
#       - nothing: user is authenticated and process
#                  returns true
212
sub controlExistingSession {
213
    my $self    = shift;
214
    my %cookies = fetch CGI::Cookie;
215

216
    # Test if Lemonldap::NG cookie is available
217 218 219
    if ( $cookies{ $self->{cookieName} }
        and my $id = $cookies{ $self->{cookieName} }->value )
    {
Xavier Guimard's avatar
Xavier Guimard committed
220
        my %h;
221

222 223
        # Trying to recover session from global session storage
        eval {
Xavier Guimard's avatar
Xavier Guimard committed
224
            tie %h, $self->{globalStorage}, $id, $self->{globalStorageOptions};
225
        };
Xavier Guimard's avatar
Xavier Guimard committed
226
        if ( $@ or not tied(%h) ) {
227

228
            # Session not available (expired ?)
229 230
            print STDERR
              "Session $id isn't yet available ($ENV{REMOTE_ADDR})\n";
231 232
            return PE_OK;
        }
Xavier Guimard's avatar
Xavier Guimard committed
233

234
        # Logout if required
235 236
        if ( $self->param('logout') ) {

237
            # Delete session in global storage
Xavier Guimard's avatar
Xavier Guimard committed
238
            tied(%h)->delete;
239

240 241 242
            # Delete cookie
            $self->{id} = "";
            $self->buildCookie();
243 244 245
            if ( $self->{urldc} ) {
                $self->{error} = PE_REDIRECT;
                if ( $self->{autoRedirect} ) {
246 247 248 249 250 251
                    &{ $self->{autoRedirect} }($self);
                }
                else {
                    $self->autoRedirect();
                }
            }
Xavier Guimard's avatar
Xavier Guimard committed
252 253
            return PE_FIRSTACCESS;
        }
254
        $self->{id} = $id;
255

256
        # A session has been find => calling &existingSession
257
        my ( $r, $datas );
Xavier Guimard's avatar
Xavier Guimard committed
258 259
        %$datas = %h;
        untie(%h);
260
        if ( $self->{existingSession} ) {
261
            $r = &{ $self->{existingSession} }( $self, $id, $datas );
262 263
        }
        else {
264
            $r = $self->existingSession( $id, $datas );
265
        }
266
        if ( $r == PE_DONE ) {
267
            $self->{error} = $self->_subProcess(qw(log autoRedirect));
268 269 270 271 272 273 274 275 276 277
            return $self->{error} || PE_DONE;
        }
        else {
            return $r;
        }
    }
    PE_OK;
}

sub existingSession {
278
    my ( $self, $id, $datas ) = @_;
279 280 281
    PE_OK;
}

Xavier Guimard's avatar
Xavier Guimard committed
282 283
# Unused. You can overload if you have to modify user and password before
# authentication
284 285 286 287
sub formateParams() {
    PE_OK;
}

Xavier Guimard's avatar
Xavier Guimard committed
288 289
# 4. By default, the user is searched in the LDAP server with its UID. To use
#    it with Active Directory, overload it to use CN instead of UID.
290 291
sub formateFilter {
    my $self = shift;
292 293
    $self->{filter} = $self->{authFilter} ||
      "(&(uid=" . $self->{user} . ")(objectClass=inetOrgPerson))";
294 295 296
    PE_OK;
}

Xavier Guimard's avatar
Xavier Guimard committed
297
# 5. First LDAP connexion used to find user DN with the filter defined before.
298 299
sub connectLDAP {
    my $self = shift;
300
    return PE_OK if ( $self->{ldap} );
301 302
    my $useTls = 0;
    my $tlsParam;
303
    foreach my $server ( split /[\s,]+/, $self->{ldapServer} ) {
304 305 306 307 308 309 310 311
        if ( $server =~ m{^ldap\+tls://([^/]+)/?\??(.*)$} ) {
            $useTls   = 1;
            $server   = $1;
            $tlsParam = $2 || "";
        }
        else {
            $useTls = 0;
        }
312 313
        last
          if $self->{ldap} = Net::LDAP->new(
314
            $server,
315 316
            port    => $self->{ldapPort},
            onerror => undef,
317
          );
318 319
    }
    return PE_LDAPCONNECTFAILED unless ( $self->{ldap} );
320
    if ($useTls) {
321 322 323 324 325
        my %h = split( /[&=]/, $tlsParam );
        $h{cafile} = $self->{caFile} if ( $self->{caFile} );
        $h{capath} = $self->{caPath} if ( $self->{caPath} );
        my $mesg = $self->{ldap}->start_tls(%h);
        $mesg->code && return PE_LDAPCONNECTFAILED;
326
    }
327 328 329
    PE_OK;
}

330
# 6. LDAP bind with Lemonldap::NG account or anonymous unless defined
331 332 333 334
sub bind {
    my $self = shift;
    $self->connectLDAP unless ( $self->{ldap} );
    return PE_WRONGMANAGERACCOUNT
335
      unless (
336 337 338 339
        $self->_bind(
            $self->{ldap}, $self->{managerDn}, $self->{managerPassword}
        )
      );
340 341 342
    PE_OK;
}

Xavier Guimard's avatar
Xavier Guimard committed
343
# 7. Search the DN
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
sub search {
    my $self = shift;
    my $mesg = $self->{ldap}->search(
        base   => $self->{ldapBase},
        scope  => 'sub',
        filter => $self->{filter},
    );
    if ( $mesg->code() != 0 ) {
        print STDERR $mesg->error . "\n";
        return PE_LDAPERROR;
    }
    return PE_USERNOTFOUND unless ( $self->{entry} = $mesg->entry(0) );
    $self->{dn} = $self->{entry}->dn();
    PE_OK;
}

360 361
# sub setAuthSessionInfo has to be defined in auth module

Xavier Guimard's avatar
Xavier Guimard committed
362 363 364
# 8. Load all parameters included in exportedVars parameter.
#    Multi-value parameters are loaded in a single string with
#    '; ' separator
365 366 367
sub setSessionInfo {
    my ($self) = @_;
    $self->{sessionInfo}->{dn} = $self->{dn};
368 369
    $self->{sessionInfo}->{startTime} =
      &POSIX::strftime( "%Y%m%d%H%M%S", localtime() );
370 371
    unless ( $self->{exportedVars} ) {
        foreach (qw(uid cn mail)) {
372 373
            $self->{sessionInfo}->{$_} =
              join( '; ', $self->{entry}->get_value($_) ) || "";
374 375 376 377
        }
    }
    elsif ( ref( $self->{exportedVars} ) eq 'HASH' ) {
        foreach ( keys %{ $self->{exportedVars} } ) {
378 379 380 381 382 383 384 385 386
            if ( my $tmp = $ENV{$_} ) {
                $tmp =~ s/[\r\n]/ /gs;
                $self->{sessionInfo}->{$_} = $tmp;
            }
            else {
                $self->{sessionInfo}->{$_} = join( '; ',
                    $self->{entry}->get_value( $self->{exportedVars}->{$_} ) )
                  || "";
            }
387 388 389
        }
    }
    else {
390
        die('Only hash reference are supported now in exportedVars');
391 392 393 394
    }
    PE_OK;
}

Xavier Guimard's avatar
Xavier Guimard committed
395
# 9. Unused here, but overloaded in SharedConf.pm
396 397 398 399 400
sub setMacros {
    PE_OK;
}

# 10. Unused here, but overloaded in SharedConf.pm
401 402 403 404
sub setGroups {
    PE_OK;
}

405
# 11. Now, LDAP will not be used by Lemonldap::NG except for LDAP
Xavier Guimard's avatar
Xavier Guimard committed
406
#     authentication scheme
407 408 409 410 411 412 413
sub unbind {
    my $self = shift;
    $self->{ldap}->unbind if $self->{ldap};
    delete $self->{ldap};
    PE_OK;
}

414
# 13. Now, the user is authenticated. It's time to store his parameters with
Xavier Guimard's avatar
Xavier Guimard committed
415
#     Apache::Session::* module
416 417 418
sub store {
    my ($self) = @_;
    my %h;
419 420 421
    eval {
        tie %h, $self->{globalStorage}, undef, $self->{globalStorageOptions};
    };
422
    if ($@) {
423 424 425
        print STDERR "$@\n";
        return PE_APACHESESSIONERROR;
    }
426
    $self->{id} = $h{_session_id};
427 428
    $h{$_} = $self->{sessionInfo}->{$_}
      foreach ( keys %{ $self->{sessionInfo} } );
429 430 431 432 433
    $h{_utime} = time();
    untie %h;
    PE_OK;
}

434
# 14. If all is done, we build the Lemonldap::NG cookie
435 436
sub buildCookie {
    my $self = shift;
437
    push @{$self->{cookie}}, $self->cookie(
438 439 440 441 442 443 444 445 446 447
        -name   => $self->{cookieName},
        -value  => $self->{id},
        -domain => $self->{domain},
        -path   => "/",
        -secure => $self->{securedCookie},
        @_,
    );
    PE_OK;
}

448
# 15. By default, nothing is logged. Users actions are logged on applications.
Xavier Guimard's avatar
Xavier Guimard committed
449 450 451 452 453 454 455 456 457 458 459 460 461
#     It's easy to override this in the contructor :
#       my $portal = new Lemonldap::NG::Portal ( {
#                    ...
#                    log => sub {use Sys::Syslog; syslog;
#                                openlog("Portal $$", 'ndelay', 'auth');
#                                syslog('notice', 'User '.$self->{user}.' is authenticated');
#                               },
#                   ...
#                 } );
sub log {
    PE_OK;
}

462
# 16. If the user was redirected to the portal, we will now redirect him
Xavier Guimard's avatar
Xavier Guimard committed
463
#     to the requested URL
464 465 466
sub autoRedirect {
    my $self = shift;
    if ( my $u = $self->{urldc} ) {
467
        $self->updateStatus;
468 469 470 471 472 473 474 475 476 477 478 479
        print $self->SUPER::redirect(
            -uri    => $u,
            -cookie => $self->{cookie},
            -status => '302 Moved Temporary'
        );

        # Remove this lines if your browsers does not support redirections
        #        print << "EOF";
        #<html>
        #<head>
        #<script language="Javascript">
        #function redirect() {
Xavier Guimard's avatar
Xavier Guimard committed
480
        #        document.location.href='$u';
481 482 483 484
        #}
        #</script>
        #</head>
        #<body onload="redirect();">
Xavier Guimard's avatar
Xavier Guimard committed
485
        #        <h2>The document has moved <a href="$u">HERE</a></h2>
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
        #</body>
        #</html>
        #EOF
        exit;
    }
    PE_OK;
}

1;

__END__

=head1 NAME

Lemonldap::NG::Portal::Simple - Base module for building Lemonldap::NG compatible portals

=head1 SYNOPSIS

  use Lemonldap::NG::Portal::Simple;
  my $portal = new Lemonldap::NG::Portal::Simple(
506
         domain         => 'example.com',
507
         globalStorage  => 'Apache::Session::MySQL',
Xavier Guimard's avatar
Xavier Guimard committed
508 509 510 511 512 513 514 515 516
         globalStorageOptions => {
           DataSource   => 'dbi:mysql:database=dbname;host=127.0.0.1',
           UserName     => 'db_user',
           Password     => 'db_password',
           TableName    => 'sessions',
           LockDataSource   => 'dbi:mysql:database=dbname;host=127.0.0.1',
           LockUserName     => 'db_user',
           LockPassword     => 'db_password',
         },
517
         ldapServer     => 'ldap.domaine.com,ldap-backup.domaine.com',
Xavier Guimard's avatar
Xavier Guimard committed
518 519
         securedCookie  => 1,
         exportedVars  => ["uid","cn","mail","appli"],
520 521 522 523 524
    );

  if($portal->process()) {
    # Write here the menu with CGI methods. This page is displayed ONLY IF
    # the user was not redirected here.
525
    print $portal->header('text/html; charset=utf8'); # DON'T FORGET THIS (see L<CGI(3)>)
526 527 528 529 530 531 532 533 534
    print "...";

    # or redirect the user to the menu
    print $portal->redirect( -uri => 'https://portal/menu');
  }
  else {
    # Write here the html form used to authenticate with CGI methods.
    # $portal->error returns the error message if athentification failed
    # Warning: by defaut, input names are "user" and "password"
535
    print $portal->header('text/html; charset=utf8'); # DON'T FORGET THIS (see L<CGI(3)>)
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
    print "...";
    print '<form method="POST">';
    # In your form, the following value is required for redirection
    print '<input type="hidden" name="url" value="'.$portal->param('url').'">';
    # Next, login and password
    print 'Login : <input name="user"><br>';
    print 'Password : <input name="password" type="password" autocomplete="off">';
    print '<input type="submit" value="go" />';
    print '</form>';
  }

=head1 DESCRIPTION

Lemonldap::NG::Portal::Simple is the base module for building Lemonldap::NG
compatible portals. You can use it either by inheritance or by writing
anonymous methods like in the example above.

Xavier Guimard's avatar
Xavier Guimard committed
553
See L<Lemonldap::NG::Portal::SharedConf> for a complete example of use of
554 555 556 557 558 559 560 561 562 563
Lemonldap::Portal::* libraries.

=head1 METHODS

=head2 Constructor (new)

=head3 Args

=over

564 565 566
=item * ldapServer: server(s) used to retrive session informations and to valid
credentials (localhost by default). More than one server can be set here
separated by commas. The servers will be tested in the specifies order.
567 568 569 570 571
To use TLS, set "ldap+tls://server" and to use LDAPS, set "ldaps://server"
instead of server name. If you use TLS, you can set any of the
Net::LDAP->start_tls() sub like this:
  "ldap/tls://server/verify=none&capath=/etc/ssl"
You can also use caFile and caPath parameters.
572 573 574 575 576 577 578 579 580 581 582

=item * ldapPort: tcp port used by ldap server.

=item * ldapBase: base of the ldap directory.

=item * managerDn: dn to used to connect to ldap server. By default, anonymous
bind is used.

=item * managerPassword: password to used to connect to ldap server. By
default, anonymous bind is used.

583
=item * securedCookie: set it to 1 if you want to protect user cookies.
584

585
=item * cookieName: name of the cookie used by Lemonldap::NG (lemon by default).
586 587 588 589 590

=item * domain: cookie domain. You may have to give it else the SSO will work
only on your server.

=item * globalStorage: required: L<Apache::Session> library to used to store
591
session informations.
592 593 594 595 596 597 598 599 600 601 602 603

=item * globalStorageOptions: parameters to bind to L<Apache::Session> module

=item * authentication: sheme to authenticate users (default: "ldap"). It can
be set to:

=over

=item * B<SSL>: See L<Lemonldap::NG::Portal::AuthSSL>.

=back

604 605 606 607
=item * caPath, caFile: if you use ldap+tls you can overwrite cafile or capath
options with those parameters. This is usefull if you use a shared
configuration.

608 609
=item * ldapPpolicyControl: set it to 1 if you want to use LDAP Password Policy

610 611 612 613
=back

=head2 Methods that can be overloaded

614
All the functions above can be overloaded to adapt Lemonldap::NG to your
615 616 617 618 619
environment. They MUST return one of the exported constants (see above)
and are called in this order by process().

=head3 controlUrlOrigin

620
If the user was redirected by a Lemonldap::NG handler, stores the url that will be
621 622 623 624
used to redirect the user after authentication.

=head3 controlExistingSession

625 626 627 628 629 630 631 632 633 634
Controls if a previous session is always available. If true, it call the sub
C<existingSession> with two parameters: id and a scalar tied on Apache::Session
module choosed to store sessions. See bellow

=head3 existingSession

This sub is called only if a previous session exists and is available. By
defaults, it returns PE_OK so user is re-authenticated. You can overload it:
for example if existingSession just returns PE_DONE: authenticated users are
not re-authenticated and C<>process> returns true.
635 636 637 638 639 640 641 642 643 644 645 646 647 648

=head3 extractFormInfo

Converts form input into object variables ($self->{user} and
$self->{password}).

=head3 formateParams

Does nothing. To be overloaded if needed.

=head3 formateFilter

Creates the ldap filter using $self->{user}. By default :

649
  $self->{filter} = "(&(uid=" . $self->{user} . ")(objectClass=inetOrgPerson))";
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690

=head3 connectLDAP

Connects to LDAP server.

=head3 bind

Binds to the LDAP server using $self->{managerDn} and $self->{managerPassword}
if exist. Anonymous bind is provided else.

=head3 search

Retrives the LDAP entry corresponding to the user using $self->{filter}.

=head3 setSessionInfo

Prepares variables to store in central cache (stored temporarily in
C<$self->{sessionInfo}>). It use C<exportedVars> entry (passed to the new sub)
if defined to know what to store else it stores uid, cn and mail attributes.

=head3 setGroups

Does nothing by default.

=head3 authenticate

Authenticates the user by rebinding to the LDAP server using the dn retrived
with search() and the password.

=head3 store

Stores the informations collected by setSessionInfo into the central cache.
The portal connects the cache using the L<Apache::Session> module passed by
the globalStorage parameters (see constructor).

=head3 unbind

Disconnects from the LDAP server.

=head3 buildCookie

691
Creates the Lemonldap::NG cookie.
692 693 694 695 696

=head3 log

Does nothing. To be overloaded if wanted.

Xavier Guimard's avatar
Xavier Guimard committed
697 698 699 700
=head3 autoRedirect

Redirects the user to the url stored by controlUrlOrigin().

701 702 703 704 705 706 707 708 709 710 711 712 713
=head2 Other methods

=head3 process

Main method.

=head3 error

Returns the error message corresponding to the error returned by the methods
described above

=head3 _bind( $ldap, $dn, $password )

714
Method used to bind to the ldap server.
715 716 717

=head3 header

718
Overloads the CGI::header method to add Lemonldap::NG cookie.
719 720 721

=head3 redirect

722
Overloads the CGI::redirect method to add Lemonldap::NG cookie.
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754

=head2 EXPORT

=head3 Constants

=over 5

=item * B<PE_OK>: all is good

=item * B<PE_SESSIONEXPIRED>: the user session has expired

=item * B<PE_FORMEMPTY>: Nothing was entered in the login form

=item * B<PE_USERNOTFOUND>: the user was not found in the (ldap) directory

=item * B<PE_WRONGMANAGERACCOUNT>: the account used to bind to LDAP server in order to
find the user distinguished name (dn) was refused by the server

=item * B<PE_BADCREDENTIALS>: bad login or password

=item * B<PE_LDAPERROR>: abnormal error from ldap

=item * B<PE_APACHESESSIONERROR>: abnormal error from Apache::Session

=item * B<PE_FIRSTACCESS>: First access to the portal

=item * B<PE_BADCERTIFICATE>: Wrong certificate

=back

=head1 SEE ALSO

755 756
L<Lemonldap::NG::Handler>, L<Lemonldap::NG::Portal::SharedConf>, L<CGI>,
http://wiki.lemonldap.objectweb.org/xwiki/bin/view/NG/Presentation
757 758 759 760 761

=head1 AUTHOR

Xavier Guimard, E<lt>x.guimard@free.frE<gt>

Xavier Guimard's avatar
Xavier Guimard committed
762 763 764 765 766 767 768 769 770 771
=head1 BUG REPORT

Use OW2 system to report bug or ask for features:
L<http://forge.objectweb.org/tracker/?group_id=274>

=head1 DOWNLOAD

Lemonldap::NG is available at
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>

772 773
=head1 COPYRIGHT AND LICENSE

774
Copyright (C) 2005-2007 by Xavier Guimard E<lt>x.guimard@free.frE<gt>
775 776 777 778 779 780

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.4 or,
at your option, any later version of Perl 5 you may have available.

=cut