Tests.pm 21.6 KB
Newer Older
Xavier Guimard's avatar
Xavier Guimard committed
1 2
package Lemonldap::NG::Manager::Conf::Tests;

Xavier Guimard's avatar
Xavier Guimard committed
3
use utf8;
4
use Lemonldap::NG::Common::Regexp;
5
use Lemonldap::NG::Handler::Main;
6

Xavier Guimard's avatar
Xavier Guimard committed
7
our $VERSION = '2.0.2';
Xavier Guimard's avatar
Xavier Guimard committed
8

Xavier Guimard's avatar
Xavier Guimard committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
## @method hashref tests(hashref conf)
# Return a hash ref where keys are the names of the tests and values
# subroutines to execute.
#
# Subroutines can return one of the followings :
# -  (1)         : everything is OK
# -  (1,message) : OK with a warning
# -  (0,message) : NOK
# - (-1,message) : OK, but must be confirmed (ignored if confirm parameter is
# set
#
# Those subroutines can also modify configuration.
#
# @param $conf Configuration to test
# @return hash ref where keys are the names of the tests and values
sub tests {
    my $conf = shift;
    return {

        # 1. CHECKS

        # Check if portal is in domain
        portalIsInDomain => sub {
            return (
                1,
34
                (   index( $conf->{portal}, $conf->{domain} ) > 0
Xavier Guimard's avatar
Xavier Guimard committed
35 36 37 38 39 40
                    ? ''
                    : "Portal seems not to be in the domain $conf->{domain}"
                )
            );
        },

41 42
        # Check if portal URL is well formated
        portalURL => sub {
43 44

            # Checking for ending slash
45
            $conf->{portal} .= '/'
46
                unless ( $conf->{portal} =~ qr#/$# );
47 48 49 50 51

            # Deleting trailing ending slash
            my $regex = qr#/+$#;
            $conf->{portal} =~ s/$regex/\//;

52 53 54
            return 1;
        },

Xavier Guimard's avatar
Xavier Guimard committed
55 56 57 58 59 60 61 62 63
        # Check if virtual hosts are in the domain
        vhostInDomainOrCDA => sub {
            return 1 if ( $conf->{cda} );
            my @pb;
            foreach my $vh ( keys %{ $conf->{locationRules} } ) {
                push @pb, $vh unless ( index( $vh, $conf->{domain} ) >= 0 );
            }
            return (
                1,
64
                (   @pb
Xavier Guimard's avatar
Xavier Guimard committed
65
                    ? 'Virtual hosts '
66 67
                        . join( ', ', @pb )
                        . " are not in $conf->{domain} and cross-domain-authentication is not set"
Xavier Guimard's avatar
Xavier Guimard committed
68 69 70 71 72 73 74 75 76 77 78 79 80
                    : undef
                )
            );
        },

        # Check if virtual host do not contain a port
        vhostWithPort => sub {
            my @pb;
            foreach my $vh ( keys %{ $conf->{locationRules} } ) {
                push @pb, $vh if ( $vh =~ /:/ );
            }
            if (@pb) {
                return ( 0,
81 82 83
                          'Virtual hosts '
                        . join( ', ', @pb )
                        . " contain a port, this is not allowed" );
Xavier Guimard's avatar
Xavier Guimard committed
84 85 86 87 88 89 90 91 92 93 94 95
            }
            else { return 1; }
        },

        # Force vhost to be lowercase
        vhostUpperCase => sub {
            my @pb;
            foreach my $vh ( keys %{ $conf->{locationRules} } ) {
                push @pb, $vh if ( $vh ne lc $vh );
            }
            if (@pb) {
                return ( 0,
96 97 98
                          'Virtual hosts '
                        . join( ', ', @pb )
                        . " must be in lower case" );
Xavier Guimard's avatar
Xavier Guimard committed
99 100 101 102 103 104
            }
            else { return 1; }
        },

        # Check if "userDB" and "authentication" are consistent
        authAndUserDBConsistency => sub {
105
            foreach
106
                my $type (qw(Facebook Google OpenID OpenIDConnect SAML WebID))
107
            {
Xavier Guimard's avatar
Xavier Guimard committed
108
                return ( 0,
109 110 111
                    "\"$type\" can not be used as user database without using \"$type\" for authentication"
                    )
                    if ($conf->{userDB} =~ /$type/
Xavier Guimard's avatar
Xavier Guimard committed
112 113 114 115 116 117 118 119 120
                    and $conf->{authentication} !~ /$type/ );
            }
            return 1;
        },

        # Check that OpenID macros exists
        checkAttrAndMacros => sub {
            my @tmp;
            foreach my $k ( keys %$conf ) {
121 122 123
                if ( $k
                    =~ /^(?:openIdSreg_(?:(?:(?:full|nick)nam|languag|postcod|timezon)e|country|gender|email|dob)|whatToTrace)$/
                    )
Xavier Guimard's avatar
Xavier Guimard committed
124 125 126 127 128
                {
                    my $v = $conf->{$k};
                    $v =~ s/^$//;
                    next if ( $v =~ /^_/ );
                    push @tmp,
129 130
                        $k
                        unless (
Xavier Guimard's avatar
Xavier Guimard committed
131 132
                        defined(
                            $conf->{exportedVars}->{$v}
133
                                or defined( $conf->{macros}->{$v} )
Xavier Guimard's avatar
Xavier Guimard committed
134
                        )
135
                        );
Xavier Guimard's avatar
Xavier Guimard committed
136 137 138 139
                }
            }
            return (
                1,
140
                (   @tmp
Xavier Guimard's avatar
Xavier Guimard committed
141
                    ? 'Values of parameter(s) "'
142 143
                        . join( ', ', @tmp )
                        . '" are not defined in exported attributes or macros'
Xavier Guimard's avatar
Xavier Guimard committed
144 145 146 147 148 149 150 151
                    : ''
                )
            );
        },

        # Test that variables are exported if Google is used as UserDB
        checkUserDBGoogleAXParams => sub {
            my @tmp;
152
            if ( $conf->{userDB} =~ /^Google$/ ) {
153 154
                foreach my $k ( keys %{ $conf->{exportedVars} } ) {
                    my $v = $conf->{exportedVars}->{$k};
155 156
                    if ( $v !~ Lemonldap::NG::Common::Regexp::GOOGLEAXATTR() )
                    {
Xavier Guimard's avatar
Xavier Guimard committed
157 158 159 160 161 162
                        push @tmp, $v;
                    }
                }
            }
            return (
                1,
163
                (   @tmp
Xavier Guimard's avatar
Xavier Guimard committed
164
                    ? 'Values of parameter(s) "'
165 166
                        . join( ', ', @tmp )
                        . '" are not exported by Google'
Xavier Guimard's avatar
Xavier Guimard committed
167 168 169 170 171 172 173 174
                    : ''
                )
            );
        },

        # Test that variables are exported if OpenID is used as UserDB
        checkUserDBOpenIDParams => sub {
            my @tmp;
175
            if ( $conf->{userDB} =~ /^OpenID$/ ) {
176 177
                foreach my $k ( keys %{ $conf->{exportedVars} } ) {
                    my $v = $conf->{exportedVars}->{$k};
178 179
                    if ( $v
                        !~ Lemonldap::NG::Common::Regexp::OPENIDSREGATTR() )
Xavier Guimard's avatar
Xavier Guimard committed
180 181 182 183 184 185 186
                    {
                        push @tmp, $v;
                    }
                }
            }
            return (
                1,
187
                (   @tmp
Xavier Guimard's avatar
Xavier Guimard committed
188
                    ? 'Values of parameter(s) "'
189 190
                        . join( ', ', @tmp )
                        . '" are not exported by OpenID SREG'
Xavier Guimard's avatar
Xavier Guimard committed
191 192 193 194 195 196 197 198
                    : ''
                )
            );
        },

        # Try to use Apache::Session module
        testApacheSession => sub {
            my ( $id, %h );
199 200
            my $gc
                = Lemonldap::NG::Handler::Main->tsv->{sessionStorageModule};
Xavier Guimard's avatar
Xavier Guimard committed
201
            return 1
202 203 204
                if ( ( $gc and $gc eq $conf->{globalStorage} )
                or $conf->{globalStorage}
                =~ /^Lemonldap::NG::Common::Apache::Session::/ );
Xavier Guimard's avatar
Xavier Guimard committed
205 206 207
            eval "use $conf->{globalStorage}";
            return ( -1, "Unknown package $conf->{globalStorage}" ) if ($@);
            eval {
Xavier Guimard's avatar
Xavier Guimard committed
208
                tie %h, 'Lemonldap::NG::Common::Apache::Session', undef,
209
                    {
Xavier Guimard's avatar
Xavier Guimard committed
210 211
                    %{ $conf->{globalStorageOptions} },
                    backend => $conf->{globalStorage}
212
                    };
Xavier Guimard's avatar
Xavier Guimard committed
213 214
            };
            return ( -1, "Unable to create a session ($@)" )
215
                if ( $@ or not tied(%h) );
Xavier Guimard's avatar
Xavier Guimard committed
216 217 218 219
            eval {
                $h{a} = 1;
                $id = $h{_session_id} or return ( -1, 'No _session_id' );
                untie(%h);
Xavier Guimard's avatar
Xavier Guimard committed
220
                tie %h, 'Lemonldap::NG::Common::Apache::Session', $id,
221
                    {
Xavier Guimard's avatar
Xavier Guimard committed
222 223
                    %{ $conf->{globalStorageOptions} },
                    backend => $conf->{globalStorage}
224
                    };
Xavier Guimard's avatar
Xavier Guimard committed
225
            };
Xavier Guimard's avatar
Xavier Guimard committed
226
            return ( -1, "Unable to insert data ($@)" ) if ($@);
Xavier Guimard's avatar
Xavier Guimard committed
227
            return ( -1, "Unable to recover data stored" )
228
                unless ( $h{a} == 1 );
Xavier Guimard's avatar
Xavier Guimard committed
229 230 231
            eval { tied(%h)->delete; };
            return ( -1, "Unable to delete session ($@)" ) if ($@);
            return ( -1,
232
                'All sessions may be lost and you must restart all your Apache servers'
Xavier Guimard's avatar
Xavier Guimard committed
233
            ) if ( $gc and $conf->{globalStorage} ne $gc );
Xavier Guimard's avatar
Xavier Guimard committed
234 235 236 237 238
            return 1;
        },

        # Warn if cookie name has changed
        cookieNameChanged => sub {
Xavier Guimard's avatar
Xavier Guimard committed
239
            my $cn = Lemonldap::NG::Handler::Main->tsv->{cookieName};
Xavier Guimard's avatar
Xavier Guimard committed
240 241
            return (
                1,
242 243
                (   $cn
                        and $cn ne $conf->{cookieName}
244
                    ? 'Cookie name has changed, you must restart all your web servers'
Xavier Guimard's avatar
Xavier Guimard committed
245 246 247 248
                    : ()
                )
            );
        },
Christophe Maudoux's avatar
Christophe Maudoux committed
249

250
        # Warn if cookie TTL is equal or lower than one hour
251 252
        cookieTTL => sub {
            return 1 unless ( defined $conf->{cookieExpiration} );
253
            return ( 0, "Cookie TTL must be higher than one minute" )
254
                unless ( $conf->{cookieExpiration} == 0
Xavier Guimard's avatar
Xavier Guimard committed
255
                || $conf->{cookieExpiration} > 60 );
256
            return ( 1, "Cookie TTL should be higher or equal than one hour" )
257
                unless ( $conf->{cookieExpiration} >= 3600
258
                || $conf->{cookieExpiration} == 0 );
Christophe Maudoux's avatar
Christophe Maudoux committed
259

260 261 262
            # Return
            return 1;
        },
Xavier Guimard's avatar
Xavier Guimard committed
263

264
        # Warn if session timeout is lower than 10 minutes
265
        sessionTimeout => sub {
266
            return 1 unless ( defined $conf->{timeout} );
267
            return ( -1, "Session timeout should be higher than ten minutes" )
268
                unless ( $conf->{timeout} > 600
269 270 271 272 273 274 275
                || $conf->{timeout} == 0 );

            # Return
            return 1;
        },

        # Error if session Activity Timeout is equal or lower than one minute
276
        sessionTimeoutActivity => sub {
277 278
            return 1 unless ( defined $conf->{timeoutActivity} );
            return ( 0,
279 280 281
                "Session activity timeout must be higher or equal than one minute"
                )
                unless ( $conf->{timeoutActivity} > 59
282 283 284 285 286 287 288 289 290 291
                || $conf->{timeoutActivity} == 0 );

            # Return
            return 1;
        },

        # Error if session Activity Timeout is equal or lower than one minute
        timeoutActivityInterval => sub {
            return 1 unless ( defined $conf->{timeoutActivityInterval} );
            return ( 0,
292 293 294 295 296
                "Activity timeout interval must be lower than session activity timeout"
                )
                if ($conf->{timeoutActivity}
                and $conf->{timeoutActivity}
                <= $conf->{timeoutActivityInterval} );
297 298 299 300 301

            # Return
            return 1;
        },

Xavier Guimard's avatar
Xavier Guimard committed
302 303 304 305
        # Warn if manager seems to be unprotected
        managerProtection => sub {
            return (
                1,
306
                (   $conf->{cfgAuthor} eq 'anonymous'
Xavier Guimard's avatar
Xavier Guimard committed
307 308 309 310 311 312
                    ? 'Your manager seems to be unprotected'
                    : ''
                )
            );
        },

313
        # Test SMTP connection and authentication (warning only)
Xavier Guimard's avatar
Xavier Guimard committed
314 315 316 317 318 319 320
        smtpConnectionAuthentication => sub {

            # Skip test if no SMTP configuration
            return 1 unless ( $conf->{SMTPServer} );

            # Use SMTP
            eval "use Net::SMTP";
321
            return ( 1, "Net::SMTP module is required to use SMTP server" )
322
                if ($@);
Xavier Guimard's avatar
Xavier Guimard committed
323 324

            # Create SMTP object
325 326 327 328 329
            my $smtp = Net::SMTP->new(
                $conf->{SMTPServer},
                Timeout => 5,
                ( $conf->{SMTPPort} ? ( Port => $conf->{SMTPPort} ) : () ),
            );
330
            return ( 1,
Xavier Guimard's avatar
Xavier Guimard committed
331
                "SMTP connection to " . $conf->{SMTPServer} . " failed" )
332
                unless ($smtp);
Xavier Guimard's avatar
Xavier Guimard committed
333 334 335

            # Skip other tests if no authentication
            return 1
336
                unless ( $conf->{SMTPAuthUser} and $conf->{SMTPAuthPass} );
Xavier Guimard's avatar
Xavier Guimard committed
337 338

            # Try authentication
339
            return ( 1, "SMTP authentication failed" )
340
                unless $smtp->auth( $conf->{SMTPAuthUser},
Xavier Guimard's avatar
Xavier Guimard committed
341 342 343 344 345
                $conf->{SMTPAuthPass} );

            # Return
            return 1;
        },
346

347
        # SAML entity ID must be uniq
348 349
        samlIDPEntityIdUniqueness => sub {
            return 1
350
                unless ( $conf->{samlIDPMetaDataXML}
351 352 353 354 355
                and %{ $conf->{samlIDPMetaDataXML} } );
            my @msg;
            my $res = 1;
            my %entityIds;
            foreach my $idpId ( keys %{ $conf->{samlIDPMetaDataXML} } ) {
356 357
                unless ( $conf->{samlIDPMetaDataXML}->{$idpId}
                    ->{samlIDPMetaDataXML} =~ /entityID=(['"])(.+?)\1/si )
358 359 360 361 362 363 364 365
                {
                    push @msg, "$idpId SAML metadata has no EntityID";
                    $res = 0;
                    next;
                }
                my $eid = $2;
                if ( defined $entityIds{$eid} ) {
                    push @msg,
366
                        "$idpId and $entityIds{$eid} have the same SAML EntityID";
367 368 369 370
                    $res = 0;
                    next;
                }
                $entityIds{$eid} = $idpId;
371 372 373 374 375
            }
            return ( $res, join( ', ', @msg ) );
        },
        samlSPEntityIdUniqueness => sub {
            return 1
376
                unless ( $conf->{samlSPMetaDataXML}
377 378 379 380 381 382
                and %{ $conf->{samlSPMetaDataXML} } );
            my @msg;
            my $res = 1;
            my %entityIds;
            foreach my $spId ( keys %{ $conf->{samlSPMetaDataXML} } ) {
                unless (
383 384
                    $conf->{samlSPMetaDataXML}->{$spId}->{samlSPMetaDataXML}
                    =~ /entityID=(['"])(.+?)\1/si )
385 386 387 388 389 390 391 392
                {
                    push @msg, "$spId SAML metadata has no EntityID";
                    $res = 0;
                    next;
                }
                my $eid = $2;
                if ( defined $entityIds{$eid} ) {
                    push @msg,
393
                        "$spId and $entityIds{$eid} have the same SAML EntityID";
394 395 396 397
                    $res = 0;
                    next;
                }
                $entityIds{$eid} = $spId;
398 399 400 401
            }
            return ( $res, join( ', ', @msg ) );
        },

402
        # Try to parse combination with declared modules
403 404 405 406
        checkCombinations => sub {
            return 1 unless ( $conf->{authentication} eq 'Combination' );
            require Lemonldap::NG::Common::Combination::Parser;
            return ( 0, 'No module declared for combination' )
407
                unless ( $conf->{combModules} and %{ $conf->{combModules} } );
408 409 410 411 412 413 414 415 416 417
            my $moduleList;
            foreach my $md ( keys %{ $conf->{combModules} } ) {
                my $entry = $conf->{combModules}->{$md};
                $moduleList->{$md} = (
                      $entry->{for} == 2 ? [ undef, {} ]
                    : $entry->{for} == 1 ? [ {}, undef ]
                    :                      [ {}, {} ]
                );
            }
            eval {
418 419
                Lemonldap::NG::Common::Combination::Parser->parse(
                    $moduleList, $conf->{combination} );
420 421
            };
            return ( 0, $@ ) if ($@);
Christophe Maudoux's avatar
Christophe Maudoux committed
422

423 424 425 426
            # Return
            return 1;
        },

427 428 429 430
        # Check Combination parameters
        combinationParameters => sub {
            return 1 unless ( $conf->{authentication} eq "Combination" );
            return ( 0, "Combination rule must be defined" )
431
                unless ( $conf->{combination} );
432
            return ( 0, 'userDB must be set to "Same" to enable Combination' )
433
                unless ( $conf->{userDB} eq "Same" );
434 435 436 437 438

            # Return
            return 1;
        },

439
        # Warn if 2F dependencies seem missing
440
        sfaDependencies => sub {
441

Christophe Maudoux's avatar
Christophe Maudoux committed
442
            my $ok = 0;
443
            foreach (qw(u totp utotp yubikey)) {
Christophe Maudoux's avatar
Christophe Maudoux committed
444 445
                $ok ||= $conf->{ $_ . '2fActivation' };
                last if ($ok);
446
            }
Christophe Maudoux's avatar
Christophe Maudoux committed
447
            return 1 unless ($ok);
448 449 450 451 452 453

            # Use TOTP
            if (   $conf->{totp2fActivation}
                or $conf->{utotp2fActivation} )
            {
                eval "use Convert::Base32";
454
                return ( 1,
455
                    "Convert::Base32 module is required to enable TOTP" )
456
                    if ($@);
457 458 459 460 461 462 463
            }

            # Use U2F
            if (   $conf->{u2fActivation}
                or $conf->{utotp2fActivation} )
            {
                eval "use Crypt::U2F::Server::Simple";
464
                return ( 1,
465
                    "Crypt::U2F::Server::Simple module is required to enable U2F"
466 467
                ) if ($@);
            }
Christophe Maudoux's avatar
Christophe Maudoux committed
468

Christophe Maudoux's avatar
Christophe Maudoux committed
469 470 471
            # Use Yubikey
            if ( $conf->{yubikey2fActivation} ) {
                eval "use Auth::Yubikey_WebClient";
472
                return ( 1,
473
                    "Auth::Yubikey_WebClient module is required to enable Yubikey"
Christophe Maudoux's avatar
Christophe Maudoux committed
474 475 476
                ) if ($@);
            }

477
            # Return
478 479
            return 1;
        },
480 481 482 483

        # Warn if TOTP or U2F is enabled with UTOTP (U2F + TOTP)
        utotp => sub {
            return 1 unless ( $conf->{utotp2fActivation} );
484
            my $w = "";
485
            foreach ( 'totp', 'u' ) {
Christophe Maudoux's avatar
Christophe Maudoux committed
486
                $w .= uc($_) . "2F is activated twice \n"
487
                    if ( $conf->{ $_ . '2fActivation' } eq '1' );
488 489 490
            }
            return ( 1, ( $w ? $w : () ) );
        },
491 492

        # Warn if TOTP not 6 or 8 digits long
Xavier Guimard's avatar
Xavier Guimard committed
493
        totp2fDigits => sub {
494
            return 1 unless ( $conf->{totp2fActivation} );
Xavier Guimard's avatar
Xavier Guimard committed
495 496 497
            return 1 unless ( defined $conf->{totp2fDigits} );
            return (
                1,
498 499 500
                (
                    (          $conf->{totp2fDigits} == 6
                            or $conf->{totp2fDigits} == 8
Xavier Guimard's avatar
Xavier Guimard committed
501 502 503 504 505 506
                    )
                    ? ''
                    : 'TOTP should be 6 or 8 digits long'
                )
            );
        },
Christophe Maudoux's avatar
Christophe Maudoux committed
507

Christophe Maudoux's avatar
Christophe Maudoux committed
508
        # Test TOTP params
509 510 511
        totp2fParams => sub {
            return 1 unless ( $conf->{totp2fActivation} );
            return ( 0, 'TOTP range must be defined' )
512
                unless ( $conf->{totp2fRange} );
513
            return ( 1, "TOTP interval should be higher than 10s" )
514
                unless ( $conf->{totp2fInterval} > 10 );
515 516 517 518 519 520 521 522 523 524

            # Return
            return 1;
        },

        # Error if Yubikey client ID and secret key are missing
        # Warn if Yubikey public ID size is not 12 digits long
        yubikey2fParams => sub {
            return 1 unless ( $conf->{yubikey2fActivation} );
            return ( 0, "Yubikey client ID and secret key must be set" )
525
                unless ( defined $conf->{yubikey2fSecretKey}
526 527 528
                && defined $conf->{yubikey2fClientID} );
            return (
                1,
529
                (   ( $conf->{yubikey2fPublicIDSize} == 12 )
530 531 532 533 534 535
                    ? ''
                    : 'Yubikey public ID size should be 12 digits long'
                )
            );
        },

536 537
        # Error if REST 2F verify URL is missing
        rest2fVerifyUrl => sub {
538
            return 1 unless ( $conf->{rest2fActivation} );
539
            return ( 0, "REST 2F Verify URL must be set" )
540
                unless ( defined $conf->{rest2fVerifyUrl} );
541 542 543 544 545

            # Return
            return 1;
        },

Christophe Maudoux's avatar
Christophe Maudoux committed
546
        # Warn if 2FA is required without a registrable 2F module enabled
547 548
        required2FA => sub {
            return 1 unless ( $conf->{sfRequired} );
549

550 551
            my $msg = '';
            my $ok  = 0;
Christophe Maudoux's avatar
Christophe Maudoux committed
552
            foreach (qw(u totp yubikey)) {
553
                $ok ||= $conf->{ $_ . '2fActivation' }
554
                    && $conf->{ $_ . '2fSelfRegistration' };
Christophe Maudoux's avatar
Christophe Maudoux committed
555
                last if ($ok);
556
            }
Christophe Maudoux's avatar
Christophe Maudoux committed
557

558
            $ok ||= $conf->{'utotp2fActivation'}
559
                && ( $conf->{'u2fSelfRegistration'}
560
                || $conf->{'totp2fSelfRegistration'} );
561 562 563
            $msg
                = "A self registrable module should be enabled to require 2FA"
                unless ($ok);
564

565
            return ( 1, $msg );
566 567 568 569 570
        },

        # Error if external 2F Send or Validate command is missing
        ext2fCommands => sub {
            return 1 unless ( $conf->{ext2fActivation} );
571 572 573 574 575 576
            return ( 0, "External 2F Send command must be set" )
                unless ( defined $conf->{ext2FSendCommand} );
            unless ( defined $conf->{ext2fCodeActivation} ) {
                return ( 0, "External 2F Validate command must be set" )
                    unless ( defined $conf->{ext2FValidateCommand} );
            }
577 578 579

            # Return
            return 1;
580 581
        },

Christophe Maudoux's avatar
Christophe Maudoux committed
582
        # Warn if XSRF token TTL is higher than 10s
Xavier Guimard's avatar
Xavier Guimard committed
583
        formTimeout => sub {
Christophe Maudoux's avatar
Christophe Maudoux committed
584
            return 1 unless ( defined $conf->{formTimeout} );
585
            return ( 0, "XSRF form token TTL must be higher than 30s" )
586
                unless ( $conf->{formTimeout} > 30 );
Christophe Maudoux's avatar
Christophe Maudoux committed
587
            return ( 1, "XSRF form token TTL should not be higher than 2mn" )
588
                if ( $conf->{formTimeout} > 120 );
589 590 591

            # Return
            return 1;
592
        },
Christophe Maudoux's avatar
Christophe Maudoux committed
593

594 595 596
        # Warn if number of password reset retries is null
        passwordResetRetries => sub {
            return 1 unless ( $conf->{portalDisplayResetPassword} );
597 598 599
            return ( 1,
                "Number of reset password retries should not be null" )
                unless ( $conf->{passwordResetAllowedRetries} );
600 601 602 603 604

            # Return
            return 1;
        },

605
        # Warn if bruteForceProtection enabled without History
606 607 608
        bruteForceProtection => sub {
            return 1 unless ( $conf->{bruteForceProtection} );
            return ( 1,
609
                '"History" plugin is required to enable "BruteForceProtection" plugin'
610
            ) unless ( $conf->{loginHistoryEnabled} );
611
            return ( 1,
612
                'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
613
            ) unless ( $conf->{failedLoginNumber} > 2 );
614 615 616

            # Return
            return 1;
Xavier Guimard's avatar
Xavier Guimard committed
617
        },
618

619 620 621
        # Warn if Mailrest plugin is enabled without Token or Captcha
        checkMailResetSecurity => sub {
            return 1 unless ( $conf->{portalDisplayResetPassword} );
622
            return ( -1,
623 624 625
                '"passwordMailReset" plugin is enabled without CSRF Token neither Captcha required !!!'
                )
                unless ( $conf->{requireToken}
626
                or $conf->{captcha_mail_enabled} );
627 628 629 630

            # Return
            return 1;
        },
631

Xavier Guimard's avatar
Xavier Guimard committed
632 633 634 635
    };
}

1;