File Coverage

blib/lib/Lemonldap/Portal/Standard.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             package Lemonldap::Portal::Standard;
3              
4 1     1   24258 use strict;
  1         2  
  1         41  
5 1     1   5 use warnings;
  1         2  
  1         29  
6 1     1   962 use Net::LDAP;
  1         216735  
  1         7  
7 1     1   87 use IO::Socket;
  1         2  
  1         8  
8 1     1   1985 use MIME::Base64;
  1         847  
  1         61  
9 1     1   2823 use Data::Dumper;
  1         11098  
  1         85  
10 1     1   11 use Net::LDAP::Constant qw(LDAP_SUCCESS LDAP_INVALID_CREDENTIALS LDAP_OPERATIONS_ERROR);
  1         2  
  1         81  
11 1     1   638 use Crypt::SaltedHash;
  0            
  0            
12             our $VERSION = '3.2.1';
13             #--------------------------------------------------------------------------------------------------
14             sub new {
15             my $class =shift;
16             my %args = @_ ;
17             my $self= bless {
18             },ref($class)||$class;
19             $self->{controlUrlOrigin} =\&__controlUrlOrigin;
20             $self->{controlCache} =\&__controlCache;
21             $self->{controlTimeOut} =\&__controlTimeOut;
22             $self->{controlSyntax} =\&__controlSyntax;
23             $self->{controlIP} =\&__controlIP;
24             $self->{bind} =\&__bind;
25             $self->{formateUser} =\&__none;
26             $self->{formateFilter} =\&__Filter;
27             $self->{formateBaseLDAP} =\&__none;
28             $self->{contactServer} =\&__contactServer;
29             $self->{search} =\&__ldapsearch;
30             $self->{setSessionInfo} =\&__session;
31             $self->{unbind} =\&__unbind;
32             $self->{credentials} =\&__credentials;
33             my $mess= { 1 => 'Votre connection a expir�. Vous devez vous authentifier de nouveau.',
34             2 => 'Les champs \'login\' et \'mot de passe \' doivent etre remplis',
35             3 => 'L\'identifiant ou le mot de passe administrateur est incorrect' ,
36             4 => 'Recherche LDAP infructueuse',
37             5 => 'wrong credentials' ,
38             6 => 'Votre adresse IP a chang�, vous devez vous authentifier de nouveau',
39             9 => 'Service Indisponible.
Le serveur de cache est injoignable, veuillez signaler ce problème à votre administrateur réseau.'
40             };
41              
42             $self->{msg} =$mess;
43            
44             foreach (keys %args) {
45             $self->{$_} = $args{$_};
46             }
47             return $self;
48             }
49             #--------------------------------------------------------------------------------------------------
50             ## method none : This method does nothing ..
51             #--------------------------------------------------------------------------------------------------
52             sub __none { #does ...nothing;
53             }
54             #--------------------------------------------------------------------------------------------------
55             ## method controlUrlOrigin
56             ## This method looks at param cgi 'urlc' in order to determine if
57             ## the request comes with a vip url (redirection) or for the menu
58             #--------------------------------------------------------------------------------------------------
59             sub __controlUrlOrigin {
60             my $urldc;
61             my $self = shift;
62             my $urlc = $self->{param}->{'url'};
63             my $service = $self->{param}->{'service'};
64             if ( defined($service) ) {
65             $self->{service} = $service;
66             $self->{CAS} = 'CASREQUESTED';
67             }
68             my $renew = $self->{param}->{'renew'};
69             if ( defined($renew) ) {
70             $self->{renew} = $service;
71             $self->{CAS} = 'CASREQUESTED';
72             }
73             my $gateway = $self->{param}->{'gateway'};
74             if ( defined($gateway) ) {
75             $self->{gateway} = $gateway;
76             $self->{CAS} = 'CASREQUESTED';
77             }
78            
79             if ( defined ( $urlc) ) {
80             $urldc = decode_base64($urlc);
81             # $urldc =~ s#:\d+/#/#; # Suppress port number in URL
82             $urlc = encode_base64($urldc,'');
83             $self->{'urlc'} = $urlc;
84             $self->{'urldc'} = $urldc;
85             }else{
86             undef($self->{'urlc'});
87             undef($self->{'urldc'});
88             }
89             }
90             #--------------------------------------------------------------------------------------------------
91             ## method controlTimeOut
92             ## This method looks at param cgi 'op'
93             ## if op eq 't' (like timeout) the handler couldn't retrieve the
94             ## storage session from id session
95             #--------------------------------------------------------------------------------------------------
96             sub __controlTimeOut {
97             my $self = shift;
98             my $operation = $self->{param}->{'op'};
99             $self->{operation} = $operation;
100            
101             if( defined( $operation ) and $operation eq 't' ){
102             $self->{'message'} = $self->{msg}{1} ;
103             $self->{'error'} =1 ;
104             }
105             }
106             #--------------------------------------------------------------------------------------------------
107             ## method controlCache
108             ## This method looks at param cgi 'op'
109             ## if op eq 'm' (like memcached) the handler couldn't retrieve the
110             ## storage session from id session
111             #--------------------------------------------------------------------------------------------------
112             sub __controlCache {
113             my $self = shift;
114             my $operation = $self->{param}->{'op'};
115             $self->{operation} = $operation;
116              
117             if( defined( $operation ) and $operation eq 'm' ) {
118             $self->{'message'} = $self->{msg}{9} ;
119             $self->{'error'} =10 ;
120             }
121             }
122             #--------------------------------------------------------------------------------------------------
123             ## method controlIP
124             ## This method looks at param cgi 'op'
125             ## if op eq 'i' (like IP) the handler couldn't retrieve the
126             ## storage session from id session
127             #--------------------------------------------------------------------------------------------------
128             sub __controlIP{
129             my $self = shift;
130             my $operation = $self->{param}->{'op'};
131             $self->{operation} = $operation;
132              
133             if( defined( $operation ) and $operation eq 'i' ) {
134             $self->{'message'} = $self->{msg}{6} ;
135             #Penser a trouver un code erreur.
136             $self->{'error'} =6 ;
137             }
138             }
139             #--------------------------------------------------------------------------------------------------
140             ## method controlSyntax
141             ## This method looks at param cgi 'identifant' and 'secret'
142             ##
143             #--------------------------------------------------------------------------------------------------
144             sub __controlSyntax {
145             my $self = shift;
146             my $user = $self->{param}->{'identifiant'};
147             if ( $self->{param}->{'username'} ) {
148             $user = $self->{param}->{'username'};
149             $self->{CAS} = 'CASREQUESTED';
150             }
151              
152             $self->{'user'} = $user;
153             my $password = $self->{param}->{'secret'};
154             if ( defined ($self->{param}->{'password'}) ) {
155             $password = $self->{param}->{'password'};
156             $self->{CAS} = 'CASREQUESTED';
157             }
158             if ( $self->{param}->{'lt'} ) {
159             $self->{it} = $self->{param}->{'lt'};
160             $self->{CAS} = 'CASREQUESTED';
161             }
162              
163             $self->{'password'} = $password;
164              
165             if( defined( $user ) or defined( $password ) )
166             {
167             if( ! defined( $user ) or $user eq '' or ! defined( $password ) or $password eq '' ) {
168             $self->{'message'} = $self->{msg}{2};
169             if ($self->{log}) {
170             $self->{log}->notice("User uid=$user -> \"login\" and \"password \" must not be empty");
171             } else
172             { print STDERR ("User uid=$user -> \"login\" and \"password\" must not be empty");
173             }
174             $self->{'error'} = 2 ;
175             }
176             }
177              
178             if( ! defined( $user ) and ! defined( $password ) ){
179             # empty form
180             $self->{'message'} = '';
181             $self->{'error'} = 9 ;
182             }
183             }
184             #--------------------------------------------------------------------------------------------------
185             ## Connection ldap on server and port ldap
186             #--------------------------------------------------------------------------------------------------
187             sub __contactServer {
188             my $self= shift;
189             unless ($self->{ldap}) {
190             my $ldap = Net::LDAP->new( $self->{server}, port => $self->{port},onerror => undef, ) or print STDERR ('Net::LDAP->new: '.$@);
191             $self->{ldap}= $ldap;
192             if ($self->{openldap} && $ldap){
193             &{$self->{bind}}($self);
194             }
195             }
196             }
197             #--------------------------------------------------------------------------------------------------
198             sub func_bind {
199             my $ldap = shift;
200             my $dn = shift;
201             my $password = shift;
202             my $mesg ;
203             if ($dn and defined($password)){
204             #named bind
205             $mesg = $ldap->bind( $dn, password => $password );
206             }else{
207             # anonymous bind
208             $mesg = $ldap->bind();
209             }
210             return $mesg->code();
211             }
212             #--------------------------------------------------------------------------------------------------
213             ## formate filter
214             #--------------------------------------------------------------------------------------------------
215             sub __Filter {
216             my $self=shift;
217             if ( ! defined $self->{filter} ) {
218             my $user = $self->{user};
219             my $filterattribute = $self->{Attributes};
220             my $filtre;
221             if (defined($filterattribute)){
222             $filtre = $filterattribute."=".$user;
223             }else{
224             $filtre = "uid=$user";
225             }
226             $self->{filter}=$filtre;
227             }
228             if ($self->{log} ) {
229             $self->{log}->info("LDAP Search Filter : " . $self->{filter} );
230             } else {
231             print STDERR ("LDAP Search Filter : " . $self->{filter}."\n" );
232             }
233             }
234             #--------------------------------------------------------------------------------------------------
235             ## Connection on server LDAP with manager credential
236             ## in order to extract user infos
237             #--------------------------------------------------------------------------------------------------
238             sub __bind {
239             my $self = shift;
240             __contactServer ($self);
241             if ( ! defined $self->{ldap} ) {
242             $self->{'message'} = $self->{msg}{8};
243             $self->{'error'} = 8 ;
244             return;
245             }
246             ##---------------------------------------------------------------------------
247             ## Authentification
248             ##---------------------------------------------------------------------------
249             my $mesg = &func_bind( $self->{ldap},$self->{DnManager},$self->{passwordManager} );
250            
251             if( $mesg == LDAP_INVALID_CREDENTIALS ) {
252             if ($self->{log}) {
253             $self->{log}->notice("Authentication Failed for DnManager -> Invalid Credentials : " . $self->{DnManager} );
254             } else
255             { print STDERR ("Authentication Failed for DnManager -> Invalid Credentials : " . $self->{DnManager} );
256             }
257             $self->{'message'} = $self->{msg}{3};
258             $self->{'error'} =3 ;
259             }elsif ( $mesg == LDAP_OPERATIONS_ERROR ) {
260             $self->{ldap} = undef;
261             __contactServer ($self);
262             my $mesg = &func_bind( $self->{ldap},$self->{DnManager},$self->{passwordManager} );
263             if ( $mesg == LDAP_OPERATIONS_ERROR ) {
264             if ($self->{log}) {
265             $self->{log}->notice("Authentication Failed for DnManager -> LDAP Operations Error : " . $self->{DnManager} );
266              
267             } else
268             { print STDERR ("Authentication Failed for DnManager -> LDAP Operations Error : " . $self->{DnManager} );
269             }
270             $self->{'message'} = $self->{msg}{8};
271             $self->{'error'} = 8 ;
272             $self->{ldap} = undef;
273             }
274             }elsif ( $mesg ) {
275             $self->{'message'} = $self->{msg}{8};
276             $self->{'error'} = 8 ;
277             $self->{ldap} = undef;
278             }
279             }
280             #--------------------------------------------------------------------------------------------------
281             sub __ldapsearch {
282             my $self=shift;
283             __contactServer ($self);
284              
285             if ( ! defined $self->{ldap} ) {
286             $self->{'message'} = $self->{msg}{8};
287             $self->{'error'} = 8 ;
288             return;
289             }
290              
291             my $ldap=$self->{ldap};
292             my $filter= $self->{filter};
293             my $base=$self->{branch};
294             my $mesg;
295             my @tbase;
296             @tbase = @{ $self->{'base'} } if $self->{'base'};
297             push @tbase, $self->{branch} unless @tbase;
298            
299              
300             foreach $base ( @tbase ){
301             if ($self->{log} ) {
302             $self->{log}->info("LDAP Search Operation :");
303             $self->{log}->info(" Search Base : " . $base);
304             $self->{log}->info(" Search Filter : " . $filter);
305             $self->{log}->info(" Search Attributes : " . $self->{'attrs'} );
306             } else {
307             print STDERR ("LDAP Search Operation :\n");
308             print STDERR (" Search Base : " . $base."\n");
309             print STDERR (" Search Filter : " . $filter."\n");
310             print STDERR (" Search Attributes : " . $self->{'attrs'}."\n" );
311             }
312             $mesg = $ldap->search( base => $base,
313             scope => 'sub',
314             filter => $filter,
315             attrs => $self->{'attrs'},
316             );
317            
318             if ( $mesg->code() == LDAP_OPERATIONS_ERROR) {
319             if ($self->{log} ) {
320             $self->{log}->notice("Authentication Failed for DnManager -> LDAP Operations Error : " . $self->{DnManager} );
321             } else
322             {
323             print STDERR ("Authentication Failed for DnManager -> LDAP Operations Error : " . $self->{DnManager} );
324             }
325             $self->{ldap} = undef;
326             }
327              
328             if( $mesg->code() != 0 ) {
329             if ($self->{log} ) {
330             $self->{log}->notice($mesg->error);
331             } else
332             { print STDERR ($mesg->error);
333             }
334             $self->{'message'} = $self->{msg}{8};
335             $self->{'error'} = 8 ;
336             $self->{'ldap'} = undef ;
337             return;
338             }
339              
340             if ( $mesg->count() > 0 ){
341             last;
342             }
343             }
344             if ($mesg->count() > 1 ){
345             $self->{'message'} = $self->{msg}{7};
346             $self->{'error'} = 7 ;
347             return;
348             }
349             my $retour=$mesg->entry(0);
350             my $identifiantCopy=$self->{user};
351            
352             if( ! defined( $retour )) {
353             $self->{'message'} = "$identifiantCopy :".$self->{msg}{4};
354             if ($self->{log}) {
355             $self->{log}->notice("Authentification Failed : $identifiantCopy hasn\'nt been found in the LDAP Server"); }
356             else { print STDERR ("Authentification Failed : $identifiantCopy hasn\'nt been found in the LDAP Server"); }
357             $self->{'error'} = 4 ;
358             return;
359             }
360             $self->{entry}= $retour;
361             return;
362             }
363             #--------------------------------------------------------------------------------------------------
364             ## function _session
365             #--------------------------------------------------------------------------------------------------
366             sub __session {
367             my $self =shift;
368             my %session;
369             my $entry =$self->{entry} ;
370             $session{dn} = $entry->dn();
371             $self->{dn} = $entry->dn();
372             $session{uid} = $entry->get_value('uid');
373             $session{cn} = $entry->get_value('cn');
374             $session{personaltitle} = $entry->get_value('personaltitle');
375             $session{mail} = $entry->get_value('mail');
376             $session{title} = $entry->get_value('title');
377             $self->{infosession} = \%session;
378             }
379             #--------------------------------------------------------------------------------------------------
380             ## Function unbind
381             ## do unbind;
382             #--------------------------------------------------------------------------------------------------
383             sub __unbind {
384             my $self=shift;
385             if ($self->{ldap}) {
386             $self->{ldap}->unbind;
387             $self->{'ldap'} = undef ;
388             }
389             }
390             #--------------------------------------------------------------------------------------------------
391             ## Function credentials
392             #--------------------------------------------------------------------------------------------------
393             sub __credentials {
394             my $self = shift;
395             __contactServer ($self);
396              
397             if ( ! defined $self->{ldap} ) {
398             $self->{'message'} = $self->{msg}{8};
399             $self->{'error'} = 8 ;
400             return;
401             }
402             ##---------------------------------------------------------------------------
403             ## Authentification
404             ##---------------------------------------------------------------------------
405            
406             if ($self->{openldap}){
407             my $ldap_pass = $self->{entry}->get_value('userPassword');
408             my $valid;
409            
410             if ($ldap_pass =~ /^\{SSHA\}/ ){
411             my $csh = Crypt::SaltedHash->new();
412             $valid = Crypt::SaltedHash->validate($ldap_pass, $self->{password} );
413             }else{
414             if ($ldap_pass eq $self->{password} ) {
415             $valid = 1;
416             }else{
417             $valid = 0;
418             }
419             }
420              
421             if ($valid) {
422              
423             if ($self->{log}) {
424             $self->{log}->notice("Authentication Successful for : " . $self->{dn} ); }
425             else {
426             print STDERR ("Authentication Successful for : " . $self->{dn}); }
427             }else{
428             # bad password
429             if ($self->{log} ) {
430             $self->{log}->notice("Authentication Failed -> Invalid Password for : " . $self->{dn} ); } else
431             {print STDERR ("Authentication Failed -> Invalid Password for : " . $self->{dn} ); }
432             $self->{'message'} = $self->{msg}{5};
433             $self->{'error'} = 5 ;
434             }
435            
436             }else{
437             my $mesg = &func_bind( $self->{ldap},$self->{dn},$self->{password} );
438             if( $mesg == LDAP_OPERATIONS_ERROR ) {
439             if ($self->{log} ) {
440             $self->{log}->notice("Authentication Failed -> LDAP Operations Error for : " . $self->{dn} ); }
441             else { print STDERR ("Authentication Failed -> LDAP Operations Error for : " . $self->{dn} ); }
442              
443             $self->{'message'} = $self->{msg}{8};
444             $self->{'error'} = 8 ;
445             $self->{ldap} = undef;
446             }elsif( $mesg == LDAP_INVALID_CREDENTIALS ) {
447             # bad password
448             if ($self->{log}) {
449             $self->{log}->notice("Authentication Failed -> Invalid Password for : " . $self->{dn} ); } else
450             { print STDERR ("Authentication Failed -> Invalid Password for : " . $self->{dn} );}
451             $self->{'message'} = $self->{msg}{5};
452             $self->{'error'} = 5 ;
453             }elsif ($mesg == LDAP_SUCCESS ) {
454             if ($self->{log} ) {
455             $self->{log}->notice("Authentication Successful for : " . $self->{dn} ); } else
456             { print STDERR ("Authentication Successful for : " . $self->{dn} );}
457             }
458             }
459             }
460             #--------------------------------------------------------------------------------------------------
461             sub message {
462             my $self= shift;
463             return ($self->{message});
464             }
465             #--------------------------------------------------------------------------------------------------
466             sub infoSession {
467             my $self= shift;
468             return ($self->{infosession});
469             }
470             #--------------------------------------------------------------------------------------------------
471             sub CAS {
472             my $self = shift;
473             return ( $self->{CASREQUESTED} );
474             }
475             #--------------------------------------------------------------------------------------------------
476             sub CASit {
477             my $self = shift;
478             return ( $self->{it} );
479             }
480             #--------------------------------------------------------------------------------------------------
481             sub CASservice {
482             my $self = shift;
483             return ( $self->{service} );
484             }
485             #--------------------------------------------------------------------------------------------------
486             sub getRedirection {
487             my $self= shift;
488             return ($self->{urldc});
489             }
490             #--------------------------------------------------------------------------------------------------
491             sub getAllRedirection {
492             my $self= shift;
493             return ($self->{urlc},$self->{urldc});
494             }
495             #--------------------------------------------------------------------------------------------------
496             sub user {
497             my $self= shift;
498             return ($self->{user});
499             }
500             #--------------------------------------------------------------------------------------------------
501             sub secret {
502             my $self= shift;
503             return ($self->{password});
504             }
505             #--------------------------------------------------------------------------------------------------
506             sub error {
507             my $self= shift;
508             return ($self->{error});
509             }
510             #--------------------------------------------------------------------------------------------------
511             sub process {
512             my $self = shift;
513             my %args = @_;
514            
515             foreach (keys %args) {
516             $self->{$_} = $args{$_};
517             }
518             #---------------------------------------------------------------
519             ## method process
520             ## This method step after step calls methods for dealing the
521             ## connection
522             ## step 0 : setting configuration
523             ## step 1 : manage the source of request
524             ## step 2 : manage timeout
525             ## step 3 : control the input form of user and password
526             ## step 4 : formate the user id if needing
527             ## step 5 : build the filter for the search
528             ## step 6 : build subtree for the search ldap
529             ## step 7 : make socket upon ldap server
530             ## step 8 : bind operation
531             ## step 9 : make search
532             ## step 10 : confection of %session from ldap infos
533             ## step 11 : unbind
534             ## step 12 : re-bind for validing user's credentials
535             ##-------------------------------------------------------------
536              
537             &{$self->{controlUrlOrigin}}($self); # no error avaiable in this step
538             &{$self->{controlTimeOut}}($self);
539             return ($self) if $self->{'error'} ; # it's not necessary to go next.
540             &{$self->{controlIP}}($self);
541             return ($self) if $self->{'error'} ; # it's not necessary to go next.
542             &{$self->{controlCache}}($self);
543             return ($self) if $self->{'error'} ; # it's not necessary to go next.
544             &{$self->{controlSyntax}}($self);
545             return ($self) if $self->{'error'} ; # it's not necessary to go next.
546             &{$self->{formateUser}}($self); # no error avaiable in this step
547             &{$self->{formateFilter}}($self); # no error avaiable in this step
548             &{$self->{formateBaseLDAP}}($self); # no error avaiable in this step
549             # &{$self->{contactServer}}($self); # can die if the server if unreachable: critical error
550              
551             if (!$self->{openldap}){
552             &{$self->{bind}}($self);
553             }
554              
555             if ($self->{'error'}) { # it's not necessary to go next.
556             &{$self->{unbind}}($self);
557             $self->{ldap} = undef;
558             return($self);
559             }
560             &{$self->{search}}($self) ;
561             if ($self->{'error'}){ # it's not necessary to go next.
562             if($self->{'error'} != 4){
563             &{$self->{unbind}}($self);
564             $self->{ldap} = undef;
565             }
566             return($self);
567             }
568             &{$self->{setSessionInfo}}($self); # no error avaiable in this step
569             &{$self->{unbind}}($self);
570             &{$self->{credentials}}($self);
571             &{$self->{unbind}}($self);
572             return($self);
573             }
574             1;
575              
576             __END__