Tests.pm 21.3 KB
Newer Older
Yadd's avatar
Yadd committed
1
2
package Lemonldap::NG::Manager::Conf::Tests;

Yadd's avatar
Yadd committed
3
use utf8;
4
5
use Lemonldap::NG::Common::Regexp;

Yadd's avatar
Yadd committed
6
our $VERSION = '2.0.1';
Yadd's avatar
Yadd committed
7

Yadd's avatar
Yadd committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
## @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,
33
                (   index( $conf->{portal}, $conf->{domain} ) > 0
Yadd's avatar
Yadd committed
34
35
36
37
38
39
                    ? ''
                    : "Portal seems not to be in the domain $conf->{domain}"
                )
            );
        },

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

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

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

51
52
53
            return 1;
        },

Yadd's avatar
Yadd committed
54
55
56
57
58
59
60
61
62
        # 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,
63
                (   @pb
Yadd's avatar
Yadd committed
64
                    ? 'Virtual hosts '
65
66
                        . join( ', ', @pb )
                        . " are not in $conf->{domain} and cross-domain-authentication is not set"
Yadd's avatar
Yadd committed
67
68
69
70
71
72
73
74
75
76
77
78
79
                    : 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,
80
81
82
                          'Virtual hosts '
                        . join( ', ', @pb )
                        . " contain a port, this is not allowed" );
Yadd's avatar
Yadd committed
83
84
85
86
87
88
89
90
91
92
93
94
            }
            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,
95
96
97
                          'Virtual hosts '
                        . join( ', ', @pb )
                        . " must be in lower case" );
Yadd's avatar
Yadd committed
98
99
100
101
102
103
            }
            else { return 1; }
        },

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

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

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

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

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

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

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

258
259
260
            # Return
            return 1;
        },
Yadd's avatar
Yadd committed
261

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

            # Return
            return 1;
        },

        # Error if session Activity Timeout is equal or lower than one minute
Christophe Maudoux's avatar
Christophe Maudoux committed
274
        sessionTimeoutActivity => sub {
275
276
            return 1 unless ( defined $conf->{timeoutActivity} );
            return ( 0,
277
278
279
                "Session activity timeout must be higher or equal than one minute"
                )
                unless ( $conf->{timeoutActivity} > 59
280
281
282
283
284
285
286
287
288
289
                || $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,
290
291
292
293
294
                "Activity timeout interval must be lower than session activity timeout"
                )
                if ($conf->{timeoutActivity}
                and $conf->{timeoutActivity}
                <= $conf->{timeoutActivityInterval} );
295
296
297
298
299

            # Return
            return 1;
        },

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

311
        # Test SMTP connection and authentication (warning only)
Yadd's avatar
Yadd committed
312
313
314
315
316
317
318
        smtpConnectionAuthentication => sub {

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

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

            # Create SMTP object
Christophe Maudoux's avatar
Christophe Maudoux committed
323
            my $smtp = Net::SMTP->new( $conf->{SMTPServer}, Timeout => 5 );
Yadd's avatar
Yadd committed
324
            return ( 1,
Yadd's avatar
Yadd committed
325
                "SMTP connection to " . $conf->{SMTPServer} . " failed" )
326
                unless ($smtp);
Yadd's avatar
Yadd committed
327
328
329

            # Skip other tests if no authentication
            return 1
330
                unless ( $conf->{SMTPAuthUser} and $conf->{SMTPAuthPass} );
Yadd's avatar
Yadd committed
331
332

            # Try authentication
Yadd's avatar
Yadd committed
333
            return ( 1, "SMTP authentication failed" )
334
                unless $smtp->auth( $conf->{SMTPAuthUser},
Yadd's avatar
Yadd committed
335
336
337
338
339
                $conf->{SMTPAuthPass} );

            # Return
            return 1;
        },
340

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

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

417
418
419
420
            # Return
            return 1;
        },

Christophe Maudoux's avatar
Christophe Maudoux committed
421
422
423
424
425
426
427
428
429
430
431
432
        # Check Combination parameters
        combinationParameters => sub {
            return 1 unless ( $conf->{authentication} eq "Combination" );
            return ( 0, "Combination rule must be defined" )
                unless ( $conf->{combination} );
            return ( 0, 'userDB must be set to "Same" to enable Combination' )
                unless ( $conf->{userDB} eq "Same" );

            # Return
            return 1;
        },

433
        # Warn if 2F dependencies seem missing
434
        sfaDependencies => sub {
435

Christophe Maudoux's avatar
Christophe Maudoux committed
436
            my $ok = 0;
437
            foreach (qw(u totp utotp yubikey)) {
Christophe Maudoux's avatar
Christophe Maudoux committed
438
439
                $ok ||= $conf->{ $_ . '2fActivation' };
                last if ($ok);
440
            }
Christophe Maudoux's avatar
Christophe Maudoux committed
441
            return 1 unless ($ok);
442
443
444
445
446
447

            # Use TOTP
            if (   $conf->{totp2fActivation}
                or $conf->{utotp2fActivation} )
            {
                eval "use Convert::Base32";
448
                return ( 1,
449
                    "Convert::Base32 module is required to enable TOTP" )
450
                    if ($@);
451
452
453
454
455
456
457
            }

            # Use U2F
            if (   $conf->{u2fActivation}
                or $conf->{utotp2fActivation} )
            {
                eval "use Crypt::U2F::Server::Simple";
458
                return ( 1,
459
                    "Crypt::U2F::Server::Simple module is required to enable U2F"
460
461
                ) if ($@);
            }
Christophe Maudoux's avatar
Christophe Maudoux committed
462

Christophe Maudoux's avatar
typo  
Christophe Maudoux committed
463
464
465
            # Use Yubikey
            if ( $conf->{yubikey2fActivation} ) {
                eval "use Auth::Yubikey_WebClient";
466
                return ( 1,
467
                    "Auth::Yubikey_WebClient module is required to enable Yubikey"
Christophe Maudoux's avatar
typo  
Christophe Maudoux committed
468
469
470
                ) if ($@);
            }

471
            # Return
Yadd's avatar
Yadd committed
472
473
            return 1;
        },
474
475
476
477

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

        # Warn if TOTP not 6 or 8 digits long
Yadd's avatar
Yadd committed
487
        totp2fDigits => sub {
Christophe Maudoux's avatar
Christophe Maudoux committed
488
            return 1 unless ( $conf->{totp2fActivation} );
Yadd's avatar
Yadd committed
489
490
491
            return 1 unless ( defined $conf->{totp2fDigits} );
            return (
                1,
492
493
                (   (          $conf->{totp2fDigits} == 6
                            or $conf->{totp2fDigits} == 8
Yadd's avatar
Yadd committed
494
495
496
497
498
499
                    )
                    ? ''
                    : 'TOTP should be 6 or 8 digits long'
                )
            );
        },
Christophe Maudoux's avatar
Christophe Maudoux committed
500

Christophe Maudoux's avatar
Christophe Maudoux committed
501
        # Test TOTP params
Christophe Maudoux's avatar
Christophe Maudoux committed
502
503
504
        totp2fParams => sub {
            return 1 unless ( $conf->{totp2fActivation} );
            return ( 0, 'TOTP range must be defined' )
505
                unless ( $conf->{totp2fRange} );
Christophe Maudoux's avatar
Christophe Maudoux committed
506
            return ( 1, "TOTP interval should be higher than 10s" )
507
                unless ( $conf->{totp2fInterval} > 10 );
Christophe Maudoux's avatar
Christophe Maudoux committed
508
509
510
511
512
513
514
515
516
517

            # 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" )
518
                unless ( defined $conf->{yubikey2fSecretKey}
Christophe Maudoux's avatar
Christophe Maudoux committed
519
520
521
                && defined $conf->{yubikey2fClientID} );
            return (
                1,
522
                (   ( $conf->{yubikey2fPublicIDSize} == 12 )
Christophe Maudoux's avatar
Christophe Maudoux committed
523
524
525
526
527
528
                    ? ''
                    : 'Yubikey public ID size should be 12 digits long'
                )
            );
        },

529
530
        # Error if REST 2F verify URL is missing
        rest2fVerifyUrl => sub {
Christophe Maudoux's avatar
Christophe Maudoux committed
531
            return 1 unless ( $conf->{rest2fActivation} );
532
            return ( 0, "REST 2F Verify URL must be set" )
533
                unless ( defined $conf->{rest2fVerifyUrl} );
Christophe Maudoux's avatar
Christophe Maudoux committed
534
535
536
537
538

            # Return
            return 1;
        },

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

Christophe Maudoux's avatar
Christophe Maudoux committed
543
544
            my $msg = '';
            my $ok  = 0;
Christophe Maudoux's avatar
Christophe Maudoux committed
545
            foreach (qw(u totp yubikey)) {
Christophe Maudoux's avatar
Christophe Maudoux committed
546
                $ok ||= $conf->{ $_ . '2fActivation' }
547
                    && $conf->{ $_ . '2fSelfRegistration' };
Christophe Maudoux's avatar
Christophe Maudoux committed
548
                last if ($ok);
549
            }
Christophe Maudoux's avatar
Christophe Maudoux committed
550

Christophe Maudoux's avatar
Christophe Maudoux committed
551
            $ok ||= $conf->{'utotp2fActivation'}
552
                && ( $conf->{'u2fSelfRegistration'}
Christophe Maudoux's avatar
Christophe Maudoux committed
553
                || $conf->{'totp2fSelfRegistration'} );
554
555
556
            $msg
                = "A self registrable module should be enabled to require 2FA"
                unless ($ok);
Christophe Maudoux's avatar
Christophe Maudoux committed
557

Christophe Maudoux's avatar
Christophe Maudoux committed
558
            return ( 1, $msg );
Christophe Maudoux's avatar
Christophe Maudoux committed
559
560
561
562
563
        },

        # Error if external 2F Send or Validate command is missing
        ext2fCommands => sub {
            return 1 unless ( $conf->{ext2fActivation} );
564
            return ( 0, "External 2F Send or Validate command must be set" )
565
                unless ( defined $conf->{ext2FSendCommand}
Christophe Maudoux's avatar
Christophe Maudoux committed
566
                && defined $conf->{ext2FValidateCommand} );
567
568
569

            # Return
            return 1;
570
571
        },

Christophe Maudoux's avatar
Christophe Maudoux committed
572
        # Warn if XSRF token TTL is higher than 10s
Yadd's avatar
Yadd committed
573
        formTimeout => sub {
Christophe Maudoux's avatar
Christophe Maudoux committed
574
            return 1 unless ( defined $conf->{formTimeout} );
Christophe Maudoux's avatar
Christophe Maudoux committed
575
            return ( 0, "XSRF form token TTL must be higher than 30s" )
576
                unless ( $conf->{formTimeout} > 30 );
Christophe Maudoux's avatar
Christophe Maudoux committed
577
            return ( 1, "XSRF form token TTL should not be higher than 2mn" )
578
                if ( $conf->{formTimeout} > 120 );
579
580
581

            # Return
            return 1;
582
        },
Christophe Maudoux's avatar
Christophe Maudoux committed
583

584
585
586
        # Warn if number of password reset retries is null
        passwordResetRetries => sub {
            return 1 unless ( $conf->{portalDisplayResetPassword} );
587
588
589
            return ( 1,
                "Number of reset password retries should not be null" )
                unless ( $conf->{passwordResetAllowedRetries} );
590
591
592
593
594

            # Return
            return 1;
        },

595
        # Warn if bruteForceProtection enabled without History
596
597
598
        bruteForceProtection => sub {
            return 1 unless ( $conf->{bruteForceProtection} );
            return ( 1,
599
                '"History" plugin is required to enable "BruteForceProtection" plugin'
600
            ) unless ( $conf->{loginHistoryEnabled} );
601
            return ( 1,
602
                'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
603
            ) unless ( $conf->{failedLoginNumber} > 2 );
604
605
606

            # Return
            return 1;
Yadd's avatar
Yadd committed
607
        },
608

609
610
611
        # Warn if Mailrest plugin is enabled without Token or Captcha
        checkMailResetSecurity => sub {
            return 1 unless ( $conf->{portalDisplayResetPassword} );
612
            return ( -1,
613
                '"passwordMailReset" plugin is enabled without CSRF Token or Captcha required !!!'
614
615
616
                )
                unless ( $conf->{requireToken}
                or $conf->{captcha_mail_enabled} );
617
618
619
620
621

            # Return
            return 1;
        },

Yadd's avatar
Yadd committed
622
623
624
625
    };
}

1;